为什么在SwiftUI的TabView中切换选项卡时,在o​​nDisappear之后再次调用onAppear?

时间:2020-08-04 17:52:21

标签: ios swiftui tabview

当标签项目出现,如果有任何改变我打电话API。为什么在调用onDisappear之后调用onAppear?

这是简单的示例:

struct ContentView: View {
    var body: some View {
        TabView {
            NavigationView {
                Text("Home")
                    .navigationTitle("Home")
                    .onAppear {
                        print("Home appeared")
                    }
                    .onDisappear {
                        print("Home disappeared")
                    }
            }
            .tabItem {
                Image(systemName: "house")
                Text("Home")
            }.tag(0)
        
            NavigationView {
                Text("Account")
                    .navigationTitle("Account")
                    .onAppear {
                        print("Account appeared")
                    }
                    .onDisappear {
                        print("Account disappeared")
                    }
            }
            .tabItem {
                Image(systemName: "gear")
                Text("Account")
            }.tag(1)
        }
    }
}    

只需运行上面的代码,我们将在onDisappear之后看到onAppear。

Home appeared
---After switch tab to Account---
Home disappeared
Account appeared
Home appeared

有什么办法可以避免这种情况?

3 个答案:

答案 0 :(得分:5)

这是一个很烦人的bug,想象一下这样的场景: Home view onAppear 方法包含一个重复获取数据的计时器。 通过切换到 Account 视图,计时器会被隐形触发。

解决方法:

  1. 为每个嵌入的 NavigationView 内容创建一个独立的视图
  2. 将当前选择值作为 @Binding 参数传递给独立视图

例如:

struct ContentView: View {
    @State var selected: MenuItem = .HOME

    var body: some View {
        return TabView(selection: $selected) {
            HomeView(selectedMenuItem: $selected)
                .navigationViewStyle(StackNavigationViewStyle())
                .tabItem {
                    VStack {
                        Image(systemName: "house")
                        Text("Home")
                    }
                }
                .tag(MenuItem.HOME)
            
            AccountView(selectedMenuItem: $selected)
                .navigationViewStyle(StackNavigationViewStyle())
                .tabItem {
                    VStack {
                        Image(systemName: "gear")
                        Text("Account")
                    }
                }
                .tag(MenuItem.ACCOUNT)
        }
    }
}

enum MenuItem: Int, Codable {
    case HOME
    case ACCOUNT
}

主页视图:

struct HomeView: View {

    @Binding var selectedMenuItem: MenuItem

    var body: some View {
        return Text("Home")
            .onAppear(perform: {
                if MenuItem.HOME == selectedMenuItem {
                    print("-> HomeView")
                }
            })
    }
}

帐户视图:

struct AccountView: View {

    @Binding var selectedMenuItem: MenuItem

    var body: some View {
        return Text("Account")
            .onAppear(perform: {
                if MenuItem.ACCOUNT == selectedMenuItem {
                    print("-> AccountView")
                }
            })
    }
}

答案 1 :(得分:1)

我不确定为什么您会在应用中看到这种行为。但是我可以解释为什么我会在我的应用程序中看到它。

我的设置与您非常相似,并且在iOS14 Beta上运行iOS13应用程序时也看到了相同的行为。在主屏幕中,我有一个自定义的标签栏,当显示详细信息屏幕时,该标签栏会进行动画显示。用于触发标签栏隐藏的代码是在“详细信息”屏幕的.onAppear中完成的。这触发了主屏幕被重绘,并且.onAppear被调用。由于此错误,我删除了动画并发现设置得更好,并且主屏幕.onAppear不再被调用。

因此,如果您的帐户屏幕.onAppear中的某些内容在主屏幕上具有视觉效果,请尝试将其注释掉,看看是否可以解决问题。

祝你好运。

答案 2 :(得分:0)

它可能对谁有帮助。

因为这种行为我只能在 iOS 14+ 上重现,所以我最终使用了 https://github.com/NicholasBellucci/StatefulTabView(它正确地只在显示时被调用;但不知道 it's a bug or not,但它适用于版本0.1.8) 和 iOS 13+ 上的 TabView。