Updating time text label each minute in WidgetKit
Solution 1:
A possible solution is to use the time
date style:
/// A style displaying only the time component for a date.
///
/// Text(event.startDate, style: .time)
///
/// Example output:
/// 11:23PM
public static let time: Text.DateStyle
- You need a simple
Entry
with aDate
property:
struct SimpleEntry: TimelineEntry {
let date: Date
}
- Create an
Entry
every minute until the next midnight:
struct SimpleProvider: TimelineProvider {
...
func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> Void) {
var entries = [SimpleEntry]()
let currentDate = Date()
let midnight = Calendar.current.startOfDay(for: currentDate)
let nextMidnight = Calendar.current.date(byAdding: .day, value: 1, to: midnight)!
for offset in 0 ..< 60 * 24 {
let entryDate = Calendar.current.date(byAdding: .minute, value: offset, to: midnight)!
entries.append(SimpleEntry(date: entryDate))
}
let timeline = Timeline(entries: entries, policy: .after(nextMidnight))
completion(timeline)
}
}
- Display the date using the
time
style:
struct SimpleWidgetEntryView: View {
var entry: SimpleProvider.Entry
var body: some View {
Text(entry.date, style: .time)
}
}
If you want to customise the date format you can use your own DateFormatter
:
struct SimpleWidgetEntryView: View {
var entry: SimpleProvider.Entry
static let dateFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.dateFormat = "HH:mm"
return formatter
}()
var body: some View {
Text("\(entry.date, formatter: Self.dateFormatter)")
}
}
Here is a GitHub repository with different Widget examples including the Clock Widget.
Solution 2:
Thanks very much for @pawello222's answer, but the problem with this solution is that too many stuff (24 * 60) are saved in the Timeline.
Once the widget's view contains a lot of elements (like 5 or more Text(...) in my case), then the widget will completely stop rendering on the ios real device, and xcode will report this:
2020-12-03 11:22:46.094442+0800 PixelClockWidgetExtension[660:53387]
[default] -[EXSwiftUI_Subsystem beginUsing:withBundle:] unexpectedly called multiple times.
I think one possible solution is to divide the daily time into several small pieces and save them in the Timeline multiple times.
My Environment:
- ios 14.2
- Xcode 12.2
- iPhone 12 pro