如何在 SwiftUI 中触发状态更改/重绘切换更改

Posted

技术标签:

【中文标题】如何在 SwiftUI 中触发状态更改/重绘切换更改【英文标题】:How trigger state change / redraw on toggle change in SwiftUI 【发布时间】:2021-07-05 03:57:45 【问题描述】:

我有一些项目并在视图上显示项目计数。我有一个切换,可以减少计数/项目列表中显示的内容。当我使用切换时,项目计数不会更新。我在这里想念什么?为简洁起见减少/模拟示例。

struct SampleView: View 

    @State var items:[Item]
    @State var easyMode:Bool = false
    @State var filtered:[Item] = []

    init(...) 
        // Fill items and filtered array
    

    var body: some View 

            Toggle(isOn: $easyMode, label:
                Text("Easy mode")
            )
            .onChange(of: self.easyMode, perform:  value in
                filtered = filterItems()
                //         ^^ This is running but not
                //            updating stuff
            )
            // This text field does not update when filter changes
            Text(String(filtered.count) + " items")
    

我尝试让 filterItems 在 @State var countLabel:String 中生成文本字符串并更新文本,但存在后台线程问题。所以我认为 filterItems 没有做任何事情有一些奇怪之处,因为它在一个单独的线程上。我错过了什么?谢谢!!

【问题讨论】:

【参考方案1】:

你可以试试这个:

.onChange(of: self.easyMode)  value in
    DispatchQueue.main.async 
       filtered = filterItems()
    

【讨论】:

【参考方案2】:

我刚刚获取了您的代码并使其可编译。

struct SOTest: View 
    @State var items:[String]
    @State var easyMode:Bool = false
    @State var filtered: [String]
    
    init() 
        let tmp = ["1","2_","3","4_","5_","6"]
        self.items = tmp
        self.filtered = tmp.filterStrings()
    

    var body: some View 

            Toggle(isOn: $easyMode, label:
                Text("Easy mode")
            )
            .onChange(of: self.easyMode, perform:  value in
                
                if value 
                    filtered = items.filterStrings()
                 else 
                    filtered = items
                
            )
            Text(String(filtered.count) + " items")
    


extension Array where Element == String 
    func filterStrings() -> [String] 
        self.filter $0.contains("_") 
    

一切正常。

可能您在原始代码中做错了什么,在您的问题中您丢失了一些重要的东西。

尝试在这里查看我的答案,也许您会找到隐藏问题的解决方案:SwiftUI: Forcing an Update

并且....顺便说一句,这里有更简单的方法:

struct SOTest: View 
    @State var items:[String]
    @State var easyMode:Bool = false
    @State var filtered: [String]

    init() 
        let tmp = ["1","2_","3","4_","5_","6"]
        self.items = tmp
        self.filtered = tmp.filterStrings()
    

    var body: some View 
        Toggle(isOn: $easyMode, label:
            Text("Easy mode")
        )
        
        if easyMode 
            Text(String(filtered.count) + " items")
        
        else 
            Text(String(items.count) + " items")
        
    

【讨论】:

哇!太棒了。嗯,这令人困惑,我花了一个小时试图找出它为什么不起作用....我正在慢慢地将代码从真实项目复制并粘贴到测试项目中,以找出问题所在

以上是关于如何在 SwiftUI 中触发状态更改/重绘切换更改的主要内容,如果未能解决你的问题,请参考以下文章

如何在 SwiftUI 应用生命周期中更改状态栏样式?

SwiftUI:状态栏颜色

ObservedObject 未触发视图重绘

SwiftUI 在视图之间切换

如何在 TabView SwiftUI 中保存视图的列表状态

使用tabview更改选项卡时如何使SwiftUI中的计时器保持触发