ios 从事件重新渲染SwiftUI视图

3duebb1j  于 2023-08-08  发布在  iOS
关注(0)|答案(2)|浏览(145)

我有一个SwiftUI视图,它的布局完全由一系列计算属性指定,但其中一些属性会随着时间的推移而自然变化。当它们改变得足够多时,我就可以使用一个通知,我想在那个时候重新渲染视图。问题是,我没有任何额外的状态可以保留,我宁愿不保留虚拟状态只是为了强制重新渲染。如何做到这一点?
具体来说,想象一个只显示当前日期的视图:

struct TodayView: View {
    var body: some View {
        Text(Date.now.formatted(date: .complete, time: .omitted))
    }
}

字符串
如果用户在其时区的时钟滴答超过午夜时仍停留在此屏幕上,则视图将不会刷新以显示新的一天。然而,当这种情况发生时,系统会发布.NSCalendarDayChanged(我知道不能保证它会在午夜发生,但是使用这个通知对我的用例来说已经足够好了)
我想让我的视图简单地使用这个通知并触发一个简单的重新渲染,但是一个简单的.onReceive(_:perform:)似乎并没有做到这一点:

struct TodayView: View {
    var body: some View {
        Text(Date.now.formatted(date: .complete, time: .omitted))
            .onReceive(NotificationCenter.default.publisher(for: .NSCalendarDayChanged) { _ in }
    }
}


我知道我可以保留一些实际上没有读取的虚拟状态,但更改它将触发重新渲染,基本上可以完成此任务,如以下示例:

struct TodayView: View {

    @State private var dummy = false

    var body: some View {
        Text(Date.now.formatted(date: .complete, time: .omitted))
            .onReceive(NotificationCenter.default.publisher(for: .NSCalendarDayChanged) { _ in
                dummy.toggle()
            }
    }
}


然而,如果可能的话,我希望最好避免在不必要的情况下保留多余的数据,因为它需要更多的RAM,并且在第一次没有上下文的情况下阅读代码时,目的不明确。最好是让视图从通知中重新呈现自己。我该怎么做?

kyvafyod

kyvafyod1#

你知道SwiftUI是关于状态的,对吧?就像当状态改变时,它会告诉SwiftUI更新视图。现在,您希望在一天发生变化时刷新视图,但您不希望仅仅为了它而保持一些随机状态。我明白了,少即是多,我们要保持干净。
我们在SwiftUI团队中介绍一个新朋友EnvironmentObject如何?它就像一个共享的盒子,不同的视图可以窥视,当盒子里的东西改变时,视图也会更新。
我有个好主意我们将创建这个DayChangeNotifier类,它是一个ObservableObject,这意味着当有什么变化时,它将为SwiftUI视图敲响警钟。在它里面,我们有一个currentDay属性,猜猜看,它是@Published。因此,每当currentDay发生变化时,SwiftUI就知道它是显示时间了!
我们的DayChangeNotifier还可以监听当天的变化。这就像一个闹钟,当一天的变化,它更新currentDay和繁荣!SwiftUI更新视图。
现在,回到我们的视图,TodayView。我们只是告诉它使用@EnvironmentObject监视DayChangeNotifier。每当currentDay发生变化时,TodayView就会更新。简单又干净!
它看起来是这样的:

class DayChangeNotifier: ObservableObject {
    @Published var currentDay: String = Date.now.formatted(date: .complete, time: .omitted)
    
    init() {
        NotificationCenter.default.addObserver(self, selector: #selector(updateCurrentDay), name: .NSCalendarDayChanged, object: nil)
    }
    
    @objc private func updateCurrentDay() {
        currentDay = Date.now.formatted(date: .complete, time: .omitted)
    }
}

struct TodayView: View {

    @EnvironmentObject var dayChangeNotifier: DayChangeNotifier

    var body: some View {
        Text(dayChangeNotifier.currentDay)
    }
}

字符串
只要确保我们的兄弟DayChangeNotifier在我们需要的时候就在身边。它得一直听着那天的变化,对吧?将其注入到环境中的父视图或应用程序结构中,我们就可以开始了!更少的杂乱,更清晰-这就是我们的方式!

tvz2xvvm

tvz2xvvm2#

正如其他人所说,你确实有一个你的观点所依赖的状态,否则永远不会有变化。视图所依赖的状态不是Date.now,它只是从Date.now派生而来。
就我个人而言,我不认为你需要一个可观察的对象,一个更简单的解决方案看起来像这样:

struct TodayView: View {
    @State private var dayString = Date.now.formatted(date: .complete, time: .omitted)

    var body: some View {
        Text(dayString)
            .onReceive(NotificationCenter.default.publisher(for: .NSCalendarDayChanged) { _ in
                dayString = Date.now.formatted(date: .complete, time: .omitted)
            }
    }
}

字符串

相关问题