swift - 如何在 iOS 14 Home Widget 中显示当前时间(实时)
问题描述
我正在为 ios 14 Home Widget 开发应用程序,但在显示小部件未每秒更新的当前时间(数字时钟)时遇到问题。众所周知,Apple 不允许每秒触发时间轴,还有其他方法可以通过实时更新显示当前时间吗?
我尝试了这些方法,但没有按预期工作
class NetworkManager: ObservableObject {
@Published var dateIs = Date()
init() {
startTimer() // fetch data must be called at least once
}
private func startTimer() {
let t = RepeatingTimer(timeInterval: 3)
t.eventHandler = {
DispatchQueue.main.async() {
// your UI update code
print("Timer Fired")
self.dateIs = Date()
WidgetCenter.shared.reloadAllTimelines() // reload timelines
}
if(false){ //I know this makes no sense, but it works. Go figure...
t.suspend()
}
}
t.resume()
}
}
struct Provider: TimelineProvider {
init() {
networkManager = NetworkManager()
}
@AppStorage("storedData", store: UserDefaults(suiteName: "group.com.name"))
var data: Data = Data()
func placeholder(in context: Context) -> WidgetEntry {
let entry = WidgetEntry(date: Date(), storedData: storedData[0], dateIs: networkManager.dateIs)
return entry
}
func getSnapshot(in context: Context, completion: @escaping (WidgetEntry) -> Void) {
guard let storedData: WidgetTemplate = try? JSONDecoder().decode(WidgetTemplate.self, from: data) else { return }
let entry = WidgetEntry(date: Date(), storedData: storedData, dateIs: networkManager.dateIs)
completion(entry)
}
func getTimeline(in context: Context, completion: @escaping (Timeline<WidgetEntry>) -> Void) {
guard let storedData: WidgetTemplate = try? JSONDecoder().decode(WidgetTemplate.self, from: data) else { return }
let entry = WidgetEntry(date: Date(), storedData: storedData, dateIs: networkManager.dateIs)
let currentDate = Date()
let refreshDate = Calendar.current.date(byAdding: .minute, value: 5, to: currentDate)!
let timeline = Timeline(entries: [entry], policy: .after(refreshDate))
completion(timeline)
}
}
解决方案
您不允许每秒刷新 Widget 。这就是苹果的限制。
您可以做的最好的事情是使用日期样式显示带有秒数的日期:timer
/// A style displaying a date as timer counting from now.
///
/// Text(event.startDate, style: .timer)
///
/// Example output:
/// 2:32
/// 36:59:01
public static let timer: Text.DateStyle
- 你需要一个简单
Entry
的Date
属性:
struct SimpleEntry: TimelineEntry {
let date: Date
}
- 在 中传递给定日期的午夜日期,并在下一个午夜
Entry
之后刷新时间线:
struct SimpleProvider: TimelineProvider {
...
func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> Void) {
let midnight = Calendar.current.startOfDay(for: Date())
let nextMidnight = Calendar.current.date(byAdding: .day, value: 1, to: midnight)!
let entries = [SimpleEntry(date: midnight)]
let timeline = Timeline(entries: entries, policy: .after(nextMidnight))
completion(timeline)
}
}
- 使用以下
timer
样式显示日期:
struct SimpleWidgetEntryView: View {
var entry: SimpleProvider.Entry
var body: some View {
Text(entry.date, style: .timer)
}
}
请注意,当您刷新时间线时(通过指定TimelineReloadPolicy
或调用WidgetCenter
),您设置了刷新小部件的最早时间。
不保证在特定时间刷新。
推荐阅读
- python - 在 Python 中对对象列表执行排序时在对象中插入字段
- sql-server - 带参数的 SQL 任务 MDX。SSIS
- c# - 在 Linux 上使用 C#/Mono 处理外部媒体
- odoo-view - 如何在 odoo12 中使用自定义字段填充下拉列表?
- android - 即使背景未设置为白色,工具栏背景默认为白色
- python - 使用 SMOTE 和 ADASYN 平衡图像数据集
- ruby - 如何使用“ruby-progressbar”根据已处理项目的数量而不是“成本”的数量来显示进度?
- azure - apache-spark 中的 copyMerge 方法无限期运行
- mysql - Debezium 上的参数 database.history 的确切含义是什么?
- javascript - 在 Three.js 中使用 OBJLoader 时出现 CORS 问题