更改已发布的 EnvironmentObject 属性 更改 TabView

Changing EnvironmentObject published property changes TabView

我正在编写的一个应用程序(第一个)出现了问题。我有一个包含多个视图的选项卡式视图,其中一个是设置。在设置视图中,各种元素(主要是 Toggles)绑定到全局环境对象 appData。当我 select 设置视图上的某些内容时,TabView 更改为远离设置视图的第一个选项卡。

下面的 playground 示例显示了这个问题。它是第一次这样做,但以后不会。在我的应用程序中,它每次都这样做。不知道为什么不同。要查看问题,请加载 playground 代码,单击设置,然后单击“设置”开关。它立即跳转到 MainView。应用程序数据中 isSet 的值似乎已设置。

我也在我的应用程序的模拟器(为 iPhone SE 设置)上看到了这个。

我正在使用 XCode 13.4.

import SwiftUI
import Combine
import Foundation
import PlaygroundSupport

class ApplicationData: ObservableObject
{
    @Published var isSet: Bool = false
}

struct MainView: View
{
    var body: some View
    {
        Text("Main View")
    }
}

struct SettingsView: View
{
    @EnvironmentObject var appData : ApplicationData
    
    var body: some View
    {
        Toggle("Setting", isOn: $appData.isSet)
    }
    
}

struct TabbedView: View
{
    @StateObject var appData = ApplicationData()
    @State var selection: Int = 0
    
    var body: some View
    {
        TabView(selection: $selection)
        {
            MainView().tabItem({Label("Main", systemImage: "menucard")})
            SettingsView().tabItem({Label("Settings", systemImage: "gear")})
        }
        .environmentObject(appData)
    }
}

let view = TabbedView()
let hostingVC = UIHostingController(rootView: view)
PlaygroundPage.current.liveView = hostingVC

我认为问题出在 TabView(selection:) 本身。由于您不提供 tags 来标识选项卡,因此视图在重绘时会失去跟踪。

要么使用TabView而不选择:

        TabView // here
        {
            MainView()
                .tabItem({Label("Main", systemImage: "menucard")})
            SettingsView()
                .tabItem({Label("Settings", systemImage: "gear")})
        }

或者 - 如果有选择 - 你必须提供一个 .tag() 这样选择可以跟踪选择的内容:

        TabView(selection: $selection)
        {
            MainView()
                .tabItem({Label("Main", systemImage: "menucard")})
                .tag(0) // here
            SettingsView()
                .tabItem({Label("Settings", systemImage: "gear")})
                .tag(1) // here
        }