英文:
Swift/Widget Extension - Time update every second
问题
Here's the translated code you requested:
这是我的第一篇帖子,请告诉我是否需要更多信息。
我正在创建一个小部件,它将同时显示两个位置的当前时间。
这是我目前的代码:
```swift
import SwiftUI
import WidgetKit
struct TimeWidgetView: View {
var localTime: String
var foreignTime: String
var body: some View {
HStack(spacing: 16) {
VStack{
Text("本地时间")
.font(.title2)
.fontWeight(.bold)
.foregroundColor(.primary)
Text(localTime)
.font(.title3)
.fontWeight(.semibold)
.foregroundColor(.primary)
.multilineTextAlignment(.center)
.lineLimit(1)
.minimumScaleFactor(0.7)
}
VStack{
Text("中国时间")
.font(.title2)
.fontWeight(.bold)
.foregroundColor(.primary)
Text(foreignTime)
.font(.title3)
.fontWeight(.semibold)
.foregroundColor(.primary)
.multilineTextAlignment(.center)
.lineLimit(1)
.minimumScaleFactor(0.7)
}
}
.padding()
}
}
struct TimeWidget: Widget {
private let kind: String = "TimeWidget"
var body: some WidgetConfiguration {
StaticConfiguration(kind: kind, provider: TimeProvider()) { entry in
TimeWidgetView(localTime: entry.localTime, foreignTime: entry.foreignTime)
}
.configurationDisplayName("时间小部件")
.description("显示本地时间和中国时间。")
}
}
struct TimeProvider: TimelineProvider {
func placeholder(in context: Context) -> TimeEntry {
TimeEntry(localTime: "00:00", foreignTime: "00:00")
}
func getSnapshot(in context: Context, completion: @escaping (TimeEntry) -> Void) {
let entry = TimeEntry(localTime: "12:34", foreignTime: "23:34")
completion(entry)
}
func getTimeline(in context: Context, completion: @escaping (Timeline<TimeEntry>) -> Void) {
let currentDate = Date()
let calendar = Calendar.current
let localTimeFormatter = DateFormatter()
localTimeFormatter.dateFormat = "HH:mm:ss"
let localTime = localTimeFormatter.string(from: currentDate)
let foreignTimeFormatter = DateFormatter()
foreignTimeFormatter.timeZone = TimeZone(identifier: "Asia/Shanghai") // 设置时区为中国
foreignTimeFormatter.dateFormat = "HH:mm:ss"
let foreignTime = foreignTimeFormatter.string(from: currentDate)
let entry = TimeEntry(localTime: localTime, foreignTime: foreignTime)
let timeline = Timeline(entries: [entry], policy: .atEnd)
completion(timeline)
}
}
struct TimeEntry: TimelineEntry {
var date: Date = Date()
var localTime: String
var foreignTime: String
}
struct TimeWidget_Previews: PreviewProvider {
static var previews: some View {
TimeWidgetView(localTime: "12:34:56", foreignTime: "23:34:45")
.previewContext(WidgetPreviewContext(family: .systemMedium))
}
}
关于您的问题,您提到希望使小部件每秒更新以充当数字时钟。您可以尝试以下方法,但要注意这可能会影响电池寿命:
func getTimeline(in context: Context, completion: @escaping (Timeline<TimeEntry>) -> Void) {
var entries: [TimeEntry] = []
// 使用定时器每半秒更新小部件作为时钟
let timer = Timer.publish(every: 0.5, on: .main, in: .common).autoconnect()
let formatter = DateFormatter()
formatter.dateFormat = "HH:mm:ss"
for second in 0...59 {
let currentDate = Date().addingTimeInterval(TimeInterval(second))
let localTime = formatter.string(from: currentDate)
let foreignTimeFormatter = DateFormatter()
foreignTimeFormatter.timeZone = TimeZone(identifier: "Asia/Shanghai") // 设置时区为中国
foreignTimeFormatter.dateFormat = "HH:mm:ss"
let foreignTime = foreignTimeFormatter.string(from: currentDate)
let entry = TimeEntry(date: currentDate, localTime: localTime, foreignTime: foreignTime)
entries.append(entry)
}
let timeline = Timeline(entries: entries, policy: .atEnd)
completion(timeline)
}
这段代码使用定时器每半秒生成一个新的时间条目,从而使小部件看起来像一个数字时钟。但请注意,这可能会对设备的电池寿命产生影响,因为它会持续消耗处理能力。
英文:
This is my first post, so let me know if any more info is needed.
I am creating a widget that will display the current time for two locations at the same time.
This is the current code I have:
import SwiftUI
import WidgetKit
struct TimeWidgetView: View {
var localTime: String
var foreignTime: String
var body: some View {
HStack(spacing: 16) {
VStack{
Text("Local Time")
.font(.title2)
.fontWeight(.bold)
.foregroundColor(.primary)
Text(localTime)
.font(.title3)
.fontWeight(.semibold)
.foregroundColor(.primary)
.multilineTextAlignment(.center)
.lineLimit(1)
.minimumScaleFactor(0.7)
}
VStack{
Text("China Time")
.font(.title2)
.fontWeight(.bold)
.foregroundColor(.primary)
Text(foreignTime)
.font(.title3)
.fontWeight(.semibold)
.foregroundColor(.primary)
.multilineTextAlignment(.center)
.lineLimit(1)
.minimumScaleFactor(0.7)
}
}
.padding()
}
}
struct TimeWidget: Widget {
private let kind: String = "TimeWidget"
var body: some WidgetConfiguration {
StaticConfiguration(kind: kind, provider: TimeProvider()) { entry in
TimeWidgetView(localTime: entry.localTime, foreignTime: entry.foreignTime)
}
.configurationDisplayName("Time Widget")
.description("Displays local time and China time.")
}
}
struct TimeProvider: TimelineProvider {
func placeholder(in context: Context) -> TimeEntry {
TimeEntry(localTime: "00:00", foreignTime: "00:00")
}
func getSnapshot(in context: Context, completion: @escaping (TimeEntry) -> Void) {
let entry = TimeEntry(localTime: "12:34", foreignTime: "23:34")
completion(entry)
}
func getTimeline(in context: Context, completion: @escaping (Timeline<TimeEntry>) -> Void) {
let currentDate = Date()
let calendar = Calendar.current
let localTimeFormatter = DateFormatter()
localTimeFormatter.dateFormat = "HH:mm:ss"
let localTime = localTimeFormatter.string(from: currentDate)
let foreignTimeFormatter = DateFormatter()
foreignTimeFormatter.timeZone = TimeZone(identifier: "Asia/Shanghai") // Set time zone to China
foreignTimeFormatter.dateFormat = "HH:mm:ss"
let foreignTime = foreignTimeFormatter.string(from: currentDate)
let entry = TimeEntry(localTime: localTime, foreignTime: foreignTime)
let timeline = Timeline(entries: [entry], policy: .atEnd)
completion(timeline)
}
}
struct TimeEntry: TimelineEntry {
var date: Date = Date()
var localTime: String
var foreignTime: String
}
struct TimeWidget_Previews: PreviewProvider {
static var previews: some View {
TimeWidgetView(localTime: "12:34:56", foreignTime: "23:34:45")
.previewContext(WidgetPreviewContext(family: .systemMedium))
}
}
When I run the app/widget from Xcode, it displays the correct time, but the time doesn't change.. I don't understand how can I accomplish this.
How can I make it update every second so it works as a digital clock?
EDIT: I may found a solution, but not sure if this is a good way to go (thinking about battery life):
func getTimeline(in context: Context, completion: @escaping (Timeline<TimeEntry>) -> Void) {
var entries: [TimeEntry] = []
// Use a Timer to update the widget every half second as a clock
let timer = Timer.publish(every: 0.5, on: .main, in: .common).autoconnect()
let formatter = DateFormatter()
formatter.dateFormat = "HH:mm:ss"
for second in 0...59 {
let currentDate = Date().addingTimeInterval(TimeInterval(second))
let localTime = formatter.string(from: currentDate)
let foreignTimeFormatter = DateFormatter()
foreignTimeFormatter.timeZone = TimeZone(identifier: "Asia/Shanghai") // Set time zone to China
foreignTimeFormatter.dateFormat = "HH:mm:ss"
let foreignTime = foreignTimeFormatter.string(from: currentDate)
let entry = TimeEntry(date: currentDate, localTime: localTime, foreignTime: foreignTime)
entries.append(entry)
}
let timeline = Timeline(entries: entries, policy: .atEnd)
completion(timeline)
}
答案1
得分: 1
请查看苹果官方文档:https://developer.apple.com/documentation/widgetkit/keeping-a-widget-up-to-date
我认为如果尝试绕过这些限制,你可能只会受到“惩罚”,你的小组件会更新得更不频繁。
我还检查了是否可以在你的小组件内实现动画,以便你可以实现一个自动移动的时钟指针,而不必每秒手动更新它,但由于 WidgetKit 不支持动画,这也是不可行的。所以,我认为你想实现的目标是不可能的。
英文:
Please check the official documentation from Apple: https://developer.apple.com/documentation/widgetkit/keeping-a-widget-up-to-date
I think if you try to bypass the limitations, you may only get "punished" and your widget will be updated even less frequently.
I also checked if it's possible to implement animations within your widget, so that you can implement a moving clock hand that basically moves by itself without manually updating it every second, but that also doesn't work since animations are not available within WidgetKit. So yeah, I think what you want to achieve is just not possible.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论