You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

切换标签页时Sheet弹窗同步异常问题

切换标签页时Sheet弹窗同步异常问题

看起来你遇到的问题根源在于所有HealthView实例共享了同一个全局的triggerSheet状态变量。TabView默认会缓存已加载的标签页视图(不会立即销毁非当前标签的视图),所以当你在第一个标签关闭sheet后,triggerSheet被设为false;切换到第二个标签点击按钮打开sheet时,虽然你把triggerSheet设为true,但第一个标签里的HealthView的sheet绑定仍然在监听这个变量——那个视图不在当前显示层级,系统尝试展示它的sheet时会自动失败,进而把triggerSheet又设为false,导致当前标签的sheet刚打开就被强制关闭了。

解决方案:给每个标签页分配独立的Sheet触发状态

我们需要让每个HealthView对应专属的sheet状态,同时保留单例管理的能力以支持深链接。下面是具体的代码修改方案:

1. 重构ObsPresentation单例,为每个Tab维护独立的Sheet状态

public class ObsPresentation: ObservableObject {
    // 确保单例唯一:用let定义shared,私有化初始化方法
    public static let shared = ObsPresentation()
    private init() {}
    
    public enum Tab {
        case health1, health2
    }
    
    @Published public var currentTab: Tab = .health1 {
        didSet {
            // 切换标签时,重置其他标签的sheet状态,避免残留影响
            for tab in Tab.allCases {
                if tab != currentTab {
                    sheetTriggers[tab] = false
                }
            }
        }
    }
    
    // 用字典存储每个Tab对应的sheet触发状态
    @Published public var sheetTriggers: [Tab: Bool] = [:]
    
    @Published public var conditionOne = true 
    @Published public var conditionTwo = true
    
    // 打开指定Tab的sheet(自动重置其他Tab的状态)
    func showSheet(for tab: Tab) {
        sheetTriggers.keys.forEach { sheetTriggers[$0] = false }
        sheetTriggers[tab] = true
    }
    
    // 关闭指定Tab的sheet
    func hideSheet(for tab: Tab) {
        sheetTriggers[tab] = false
    }
}

// 给Tab枚举添加allCases,方便遍历操作
extension ObsPresentation.Tab: CaseIterable {
    public static var allCases: [ObsPresentation.Tab] {
        [.health1, .health2]
    }
}

2. 修改HealthView,绑定到对应Tab的专属Sheet状态

struct HealthView: View {
    // 每个HealthView实例对应一个明确的Tab
    let tab: ObsPresentation.Tab
    @StateObject private var obsPresentation = ObsPresentation.shared
    
    var body: some View {
        VStack() {
            ScrollView {
                // 补全LazyVGrid的列配置(示例用单列)
                LazyVGrid(columns: [GridItem(.flexible())]) {
                    Button(action: {
                        // 打开当前Tab对应的sheet
                        obsPresentation.showSheet(for: tab)
                    }) {
                        Text("打开健康详情")
                            .padding()
                            .background(Color.blue)
                            .foregroundColor(.white)
                            .cornerRadius(8)
                    }
                }
            }
        }
        // 绑定到当前Tab专属的sheet状态
        .sheet(isPresented: Binding(
            get: { obsPresentation.sheetTriggers[tab, default: false] },
            set: { if !$0 { obsPresentation.hideSheet(for: tab) } }
        )) {
            SheetView()
                .onDisappear {
                    // sheet消失时主动同步状态
                    obsPresentation.hideSheet(for: tab)
                }
        }
    }
}

3. 调整主TabView,给每个HealthView传入对应Tab标识

// 注意:避免和系统TabView重名,改名为MainTabView
struct MainTabView: View {
    @StateObject private var obsPresentation = ObsPresentation.shared
    
    var body: some View {
        ZStack {
            VStack {
                TabView(selection: $obsPresentation.currentTab) {
                    if obsPresentation.conditionOne {
                        HealthView(tab: .health1) // 传入对应Tab
                            .tabItem {
                                Label("Person 1 Health", systemImage: "heart")
                            }
                            .tag(ObsPresentation.Tab.health1)
                    }
                    
                    if obsPresentation.conditionTwo {
                        HealthView(tab: .health2) // 传入对应Tab
                            .tabItem {
                                Label("Person 2 Health", systemImage: "heart")
                            }
                            .tag(ObsPresentation.Tab.health2)
                    }
                }
            }
        }
    }
}

方案说明

  • 每个HealthView现在绑定到专属的sheet状态,不同标签页的sheet操作完全独立,不会互相干扰。
  • 深链接逻辑可以通过调用ObsPresentation.shared.showSheet(for: .health1)直接控制指定标签的sheet打开,满足需求。
  • 切换标签时会自动重置其他标签的sheet状态,避免残留的旧状态影响后续操作。

另外补充两个小细节:

  • 原来的TabView结构体和系统TabView重名了,建议改名为MainTabView避免编译混淆。
  • LazyVGrid需要明确指定列配置,示例中补全了最基础的单列配置,你可以根据实际需求调整。

备注:内容来源于stack exchange,提问作者quinner

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.15 09:17:59