WidgetKit @StateObject 不更新视图 [英] WidgetKit @StateObject not updating View

查看:30
本文介绍了WidgetKit @StateObject 不更新视图的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我无法理解如何使我的 SwiftUI 数据模型示例与我的 Widget 一起使用.它在我的测试应用程序中运行良好,我立即观察到变化.当我尝试使用 Widget 时,我可以看到在控制台中打印的数据,但在 WidgetKit 中的 View 中没有发生任何更改.我正在使用 ObservableObject 类和 @Published 变量.我尝试使用 @StateObject@ObservedObject@EnvironmentObject 并得到相同的结果.总是导致今天没有比赛.我的数据模型与 Combine 相关,不确定这是否与为什么我在 WidgetKitView 中看不到数据更改有关>.

I'm having trouble understanding how to make my SwiftUI data model example work with my Widget. It's working in my test app just fine, I observe changes immediately. When I attempt the Widget, I can see the data being printed in console but no changes are happening in my View in WidgetKit. I'm using a ObservableObject class and @Published variables. I've attempted to use a @StateObject, @ObservedObject and an @EnvironmentObject and the same results. Always results in No game today. My data model is Combine related, not sure if that has anything to do with why I can't see data changes in my WidgetKit's View.

SwiftUI 应用示例工作

struct ContentView: View {
    @ObservedObject var data = CombineData()
    @State private var showSortSheet: Bool = false
    @State private var nhlTeams: TeamOrder = .NewYorkIslanders
    
    var body: some View {
        NavigationView {
            VStack(alignment: .leading) {
                if data.schedule?.dates.first != nil {
                    Text("Game today")
                } else {
                    Text("No game today")
                }
            }
            .listStyle(PlainListStyle())
            .navigationBarTitle(Text(""), displayMode: .inline)
            .navigationBarItems(leading: HStack {
                Button(action: {
                    self.showSortSheet.toggle()
                }) {
                    HStack {
                        Image(systemName: "arrow.up.arrow.down")
                    }
                }
            })
            .actionSheet(isPresented: $showSortSheet) {
                ActionSheet(title: Text("Teams:"), buttons: [TeamOrder.NewYorkIslanders, TeamOrder.MontrealCanadiens].map { method in
                    ActionSheet.Button.default(Text("\(method.rawValue)")) {
                        self.nhlTeams = method
                        data.fetchSchedule(self.nhlTeams.rawValue)
                        print("\(self.nhlTeams.rawValue)")
                    }
                })
            }
            .onAppear {
                data.fetchSchedule(self.nhlTeams.rawValue)
            }
        }
    }
}

示例小部件 @StateObject(无数据更改)

Example Widget @StateObject (No data changes)

struct ExampleEntryView : View {
    var entry: Provider.Entry
    @Environment(\.widgetFamily) var widgetFamily
    @StateObject var model = CombineData()
    @ObservedObject var model = CombineData()
    /*@EnvironmentObject private var model: CombineData*/
    var body: some View {
        VStack(alignment: .leading) {
            if model.schedule?.dates.first != nil {
                Text("Game today")
            } else {
                Text("No game today")
            }
        }
        .onAppear {
            model.fetchSchedule(entry.configuration.teams.rawValue) {
                WidgetCenter.shared.reloadTimelines(ofKind: "NHL_Widget")
            }
        }
    }
}

示例小部件 2 TimelineEntry(无数据更改)

struct SimpleEntry: TimelineEntry {
    let date: Date
    let configuration: ConfigurationIntent
    let model: CombineData
}

struct Provider: IntentTimelineProvider {
    
    func getTimeline(for configuration: ConfigurationIntent, in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
        var entries: [SimpleEntry] = []
        let currentDate = Date()
        let model = CombineData()
        let entryDate = Calendar.current.date(byAdding: .minute, value: 1, to: currentDate)!
        let entry = SimpleEntry(date: entryDate, configuration: configuration, model: model)
        entries.append(entry)
        let timeline = Timeline(entries: entries, policy: .atEnd)
        model.fetchSchedule(entry.configuration.teams.rawValue) {
            completion(timeline)
        }
    }
}

struct ExampleEntryView : View {
    var entry: Provider.Entry
    @Environment(\.widgetFamily) var widgetFamily
    var body: some View {
        VStack(alignment: .leading) {
            if entry.model.schedule?.dates.first != nil {
                Text("Game today")
            } else {
                Text("No game today")
            }
        }
    }
}

推荐答案

小部件是静态的,您在 getTimeline 上提供的视图将按原样显示且不会更新,因此在 onAppear 上调用 fetchSchedule 甚至不会被执行.一旦您在 getTimeline 中执行完成处理程序,就不会再执行任何代码.

Widgets are static, the view you provide on getTimeline is what will be displayed as is and won't be updated, so the call to fetchSchedule on onAppear won't even be executed. Once you execute the completion handler in getTimeline, no more code is executed.

要在小部件上显示数据,您需要在 getTimeline 中获取数据,创建一个从头开始显示数据的视图,并在完成处理程序中返回该条目.

To display data on your widgets you need to fetch your data in getTimeline, create a view that displays the data from the start, and return that entry in your completion handler.

在您的最后一个示例中,我建议您在 model.fetchSchedule 的完成处理程序中创建条目并将 schedule 对象传递给您的视图.

In your last example I would suggest that you create your entry in the completion handler of model.fetchSchedule and pass the schedule object to your view.

这篇关于WidgetKit @StateObject 不更新视图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆