如何在 Swift 5 中使用 TimelineView 每秒刷新一个文本?

发布于 2025-01-12 05:14:28 字数 1059 浏览 0 评论 0原文

我对快速编码很陌生,我正在尝试做一个非常简单的项目:只是一个显示时间的时钟。我正在使用 TimelineView 每秒刷新时间,但它不起作用。这是我的代码:

import SwiftUI

struct ContentView: View {

@State var hour: Int = Calendar.current.component(.hour, from: Date())
@State var minute: Int = Calendar.current.component(.minute, from: Date())
@State var second: Int = Calendar.current.component(.second, from: Date())


var body: some View {
    ZStack {
        VStack{
            Spacer()
            HStack {
                
                TimelineView(.periodic(from: .now, by: 1)) { timeline in
                    
                    Text(String(hour))
                    Text(String(minute))
                    Text(String(second))
                }
            }
            
            Spacer()
        }


    }
}
}

struct ContentView_Previews: PreviewProvider {
   static var previews: some View {
       Group {
       ContentView()
.previewInterfaceOrientation(.portrait)
       }
   }
}

由于我的小时、分钟和秒变量是 @State 并且我正在使用 TimelineView,它们应该每秒刷新一次,不是吗?

我很困惑,希望得到一些帮助。非常感谢。

I'm pretty new at swift coding and I'm trying to do a very simple project: just a clock that shows the time. I'm using TimelineView to refresh the time every second, but it's not working. This is my code:

import SwiftUI

struct ContentView: View {

@State var hour: Int = Calendar.current.component(.hour, from: Date())
@State var minute: Int = Calendar.current.component(.minute, from: Date())
@State var second: Int = Calendar.current.component(.second, from: Date())


var body: some View {
    ZStack {
        VStack{
            Spacer()
            HStack {
                
                TimelineView(.periodic(from: .now, by: 1)) { timeline in
                    
                    Text(String(hour))
                    Text(String(minute))
                    Text(String(second))
                }
            }
            
            Spacer()
        }


    }
}
}

struct ContentView_Previews: PreviewProvider {
   static var previews: some View {
       Group {
       ContentView()
.previewInterfaceOrientation(.portrait)
       }
   }
}

Since my hour, minute and second variables are @State and I'm using the TimelineView, they should refresh every second, shouldn't they?

I'm very confused and I would appreciate some help. Thank you very much.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

丶视觉 2025-01-19 05:14:29

正如文档所述(https://developer.apple.com/documentation/swiftui/timelineview):

时间线视图充当容器,没有自己的外观。相反,它会在预定的时间点重新绘制其包含的内容

它包含的内容在您提供的闭包中定义:

TimelineView(...) { timeline in
    // content which gets redrawn
}

在这个闭包中,您可以访问 TimelineView.Context (https://developer.apple.com/documentation/swiftui/timelineview/context)。借助此上下文,您可以访问触发更新/重画的日期,如下所示:

TimelineView(.periodic(from: .now, by: 1)) { timeline in
    Text("\(timeline.date)")
}

这将产生以下输出:
输入图片此处描述

要改进格式设置,您可以使用 DateFormatter (https://developer.apple.com/documentation/foundation/dateformatter):

struct ContentView: View {
    private let dateFormatter: DateFormatter = {
        let dateFormatter = DateFormatter()
        dateFormatter.dateStyle = .none
        dateFormatter.timeStyle = .medium
        return dateFormatter
    }()
    
    var body: some View {
        TimelineView(.periodic(from: .now, by: 1)) { timeline in
            Text("\(dateFormatter.string(from: timeline.date))")
        }
    }
}

在此处输入图像描述

As the documentation says (https://developer.apple.com/documentation/swiftui/timelineview):

A timeline view acts as a container with no appearance of its own. Instead, it redraws the content it contains at scheduled points in time

The content it contains is defined in the closure you provide:

TimelineView(...) { timeline in
    // content which gets redrawn
}

Inside this closure you have access to a TimelineView.Context (https://developer.apple.com/documentation/swiftui/timelineview/context). With the help of this context, you can access the date which triggered the update / redraw like so:

TimelineView(.periodic(from: .now, by: 1)) { timeline in
    Text("\(timeline.date)")
}

This will produce the following output:
enter image description here

To improve formatting, you could use a DateFormatter (https://developer.apple.com/documentation/foundation/dateformatter):

struct ContentView: View {
    private let dateFormatter: DateFormatter = {
        let dateFormatter = DateFormatter()
        dateFormatter.dateStyle = .none
        dateFormatter.timeStyle = .medium
        return dateFormatter
    }()
    
    var body: some View {
        TimelineView(.periodic(from: .now, by: 1)) { timeline in
            Text("\(dateFormatter.string(from: timeline.date))")
        }
    }
}

enter image description here

写下不归期 2025-01-19 05:14:29

你必须观察时间线的变化。

这里我使用了 onChange 并更新了分钟、秒和小时的值。

struct TimerView: View {
    var date: Date
    
    @State var hour: Int = Calendar.current.component(.hour, from: Date())
    @State var minute: Int = Calendar.current.component(.minute, from: Date())
    @State var second: Int = Calendar.current.component(.second, from: Date())
    
    var body: some View {
        VStack {
            Text(String(hour))
            Text(String(minute))
            Text(String(second))
        }
        .onChange(of: date) { _ in
            second += 1
            if second > 59 {
                minute += 1
                second = 0
                if minute > 59 {
                    hour += 1
                    minute = 0
                    if hour > 23 {
                        hour = 0
                    }
                }
            }
        }
    }
}
struct ContentView: View { var body: some View {
        ZStack {
            VStack{
                Spacer()
                HStack {
                    TimelineView(.periodic(from: .now, by: 1)) { timeline in
                        TimerView(date: timeline.date)
                    }
                }
                Spacer()
            }
        }
    }
}

You have to observe changes in the timeline.

Here I used onChange and update the value of min, sec, and hour.

struct TimerView: View {
    var date: Date
    
    @State var hour: Int = Calendar.current.component(.hour, from: Date())
    @State var minute: Int = Calendar.current.component(.minute, from: Date())
    @State var second: Int = Calendar.current.component(.second, from: Date())
    
    var body: some View {
        VStack {
            Text(String(hour))
            Text(String(minute))
            Text(String(second))
        }
        .onChange(of: date) { _ in
            second += 1
            if second > 59 {
                minute += 1
                second = 0
                if minute > 59 {
                    hour += 1
                    minute = 0
                    if hour > 23 {
                        hour = 0
                    }
                }
            }
        }
    }
}
struct ContentView: View { var body: some View {
        ZStack {
            VStack{
                Spacer()
                HStack {
                    TimelineView(.periodic(from: .now, by: 1)) { timeline in
                        TimerView(date: timeline.date)
                    }
                }
                Spacer()
            }
        }
    }
}
源来凯始玺欢你 2025-01-19 05:14:29

只需将小时-分钟-秒作为计算属性而不是@State

struct ContentView: View {
    var hour: Int {
        Calendar.current.component(.hour, from: Date())
    }
    var minute: Int {
        Calendar.current.component(.minute, from: Date())
    }
    var second: Int {
        Calendar.current.component(.second, from: Date())
    }
    var body: some View {
        TimelineView(.periodic(from: .now, by: 1.0)) { timeline in
            HStack {
                Text(String(hour))
                Text(String(minute))
                Text(String(second))
            }
        }
    }
}

Just make your hour-minute-second as computed property not @State

struct ContentView: View {
    var hour: Int {
        Calendar.current.component(.hour, from: Date())
    }
    var minute: Int {
        Calendar.current.component(.minute, from: Date())
    }
    var second: Int {
        Calendar.current.component(.second, from: Date())
    }
    var body: some View {
        TimelineView(.periodic(from: .now, by: 1.0)) { timeline in
            HStack {
                Text(String(hour))
                Text(String(minute))
                Text(String(second))
            }
        }
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文