首页 > 解决方案 > 如何防止触发 SwiftUI TabView 中非活动选项卡的 onChange 关闭

问题描述

当设置带有两个选项卡的 SwiftUI TabView 时,监听 @State 或 @Binding 变量的非活动(不可见)选项卡的 onChange 闭包将始终在从活动选项卡更改变量时触发。

我希望只要选项卡未处于活动状态,就不会触发 onChange。使用两个不同的导航链接时,它的工作原理基本相同。但我认为它以某种方式使非活动选项卡在后台完全活跃。

我尝试为每个选项卡视图分配标签,以便视图可以识别活动选项卡。我读到这可以解决问题,但事实并非如此。

这是一个显示问题的简单 SwiftUI 应用程序。当第二个选项卡处于活动状态并且我单击按钮时,第一个选项卡的 onChange 将被触发并打印到控制台。

如果我需要提供不同的示例或有问题,请告诉我。

注意:在使用 onReceive 时也会发生这种情况,例如监听 ObservableObject 的 @Published 变量的变化。

import SwiftUI

struct ContentView: View {

    @State var tabViewSelection: String = "Ant"
    @State var value: Bool = false

    var body: some View {

        TabView(selection: $tabViewSelection) {

            AntView(value: $value)
                .tag("Ant")
                .tabItem {
                    Image(systemName: "ant")
                }

            LadybugView(value: $value)
                .tag("Ladybug")
                .tabItem {
                    Image(systemName: "ladybug")
                }
        }
    }
}

struct AntView: View {
    @Binding var value: Bool

    var body: some View {
        Text("AntView")
            .onChange(of: value) { value in
                print("onChange new value = \(value)") // <-- will get triggered...
            }
    }
}

struct LadybugView: View {
    @Binding var value: Bool

    var body: some View {
        VStack {
            Text("LadybugView")
            Button(action: {
                value.toggle() // <-- ...when changing value here.
            }, label: {
                Text("Toggle value")
            })
        }
    }
}


struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

标签: swiftswiftuiswiftui-tabview

解决方案


您要做的第一件事是分离绑定。

struct ContentView: View {

    @State var tabViewSelection: String = "Ant"
    @State var antViewValue: Bool = false
    @State var ladyViewValue: Bool = false

        var body: some View {
    
            TabView(selection: $tabViewSelection) {
    
                AntView(value: $antViewValue)
                    .tag("Ant")
                    .tabItem {
                        Image(systemName: "ant")
                    }
    
                LadybugView(value: $ladyViewValue)
                    .tag("Ladybug")
                    .tabItem {
                        Image(systemName: "ladybug")
                    }
            }
        }
    }

然后,一旦将它们分开,您将需要使用一些逻辑来确定需要更新哪个值以及何时更新。

Button(action: { 
        //Add a condition to update whatever value you're wanting to update.
        if ladyViewValue == true {
            ladyViewValue.toggle()
        } else {
            antViewValue.toggle()
        }
    }, label: { 
        Text("Toggle value")
    })

最终,您将您的价值分成两种可能的情况。这是您将要做的常见事情,并且有无数不同的方法可以做到这一点。这是一个简单的例子,也是一项关键的基础技能。您可以从中获得的最好的收获是学习将事物分解成最小的形式。


推荐阅读