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

MacOS Sonoma 14.6 MacCatalyst中三级Sheet弹窗立即消失问题求助

Mac Catalyst(Sonoma 14.6)多层Sheet弹出后自动消失问题及修复方案

问题现象

在MacOS Sonoma 14.6的Mac Catalyst环境中,若第一层Sheet是作为NavigationStack内部视图的修饰符添加(而非直接修饰NavigationStack本身),弹出第三层Sheet后会立即自动消失。该问题不会出现在MacOS 13.6的Mac Catalyst、iOS 16.4及iOS 17.6环境中。

由于实际应用中每个NavigationStack需要承载多个Sheet,因此原本采用overlay包裹EmptyView的方式实现Sheet挂载,现在需要找到兼容iOS>16及MacOS>14.6的Mac Catalyst环境的正确写法。

问题复现代码

import SwiftUI

@main
struct TestSheetsApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

struct ContentView: View {
    @State var popup1Item = false

    var body: some View {
        NavigationStack {
            Button("显示弹窗1") {
                popup1Item = true
            }
            // 这段代码会导致第三层弹窗弹出后立即消失
            .overlay(
                EmptyView()
                    .sheet(isPresented: $popup1Item) {
                        Popup1()
                    }
                )
        }
        // 这段代码能让第三层弹窗正常显示
        /*
        .overlay(
            EmptyView()
                .sheet(isPresented: $popup1Item) {
                    Popup1()
                }
            )
        */
    }
}

struct Popup2: View {
    @State var showPopup3 = false

    var body: some View {
        NavigationStack {
            Button("显示弹窗3") {
                showPopup3 = true
            }
        }
        .overlay(
            EmptyView()
                .sheet(isPresented: $showPopup3) {
                    Text("弹窗3")
                }
        )
    }
}

struct Popup1: View {
    @State var popup2Item = false
    
    var body: some View {
        NavigationStack {
            Button("显示弹窗2") {
                popup2Item = true
            }
            .overlay(
                EmptyView()
                .sheet(isPresented: $popup2Item) {
                    Popup2()
                }
            )
         }
    }
}

修复方案

核心问题在于Sonoma 14.6的Mac Catalyst对Sheet的视图层级处理有变化,将Sheet修饰符挂载到NavigationStack内部视图上时,会导致多层弹窗的状态管理异常。

正确的做法是统一将Sheet的overlay修饰符挂载到NavigationStack的外部,而非内部的Button或其他视图上。这样可以保证Sheet的状态不受NavigationStack内部视图刷新的影响,同时依然满足一个NavigationStack对应多个Sheet的需求。

修改后的代码

import SwiftUI

@main
struct TestSheetsApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

struct ContentView: View {
    @State var popup1Item = false

    var body: some View {
        NavigationStack {
            Button("显示弹窗1") {
                popup1Item = true
            }
        }
        // 将Sheet的overlay移到NavigationStack外部
        .overlay(
            EmptyView()
                .sheet(isPresented: $popup1Item) {
                    Popup1()
                }
        )
    }
}

struct Popup2: View {
    @State var showPopup3 = false

    var body: some View {
        NavigationStack {
            Button("显示弹窗3") {
                showPopup3 = true
            }
        }
        .overlay(
            EmptyView()
                .sheet(isPresented: $showPopup3) {
                    Text("弹窗3")
                }
        )
    }
}

struct Popup1: View {
    @State var popup2Item = false
    
    var body: some View {
        NavigationStack {
            Button("显示弹窗2") {
                popup2Item = true
            }
        }
        // 将Sheet的overlay移到NavigationStack外部
        .overlay(
            EmptyView()
                .sheet(isPresented: $popup2Item) {
                    Popup2()
                }
        )
    }
}

说明

  • 所有Sheet的overlay都直接修饰对应的NavigationStack,而非内部的子视图
  • 该写法兼容iOS>16及MacOS>14.6的Mac Catalyst环境,同时保留了一个NavigationStack对应多个Sheet的扩展性(可在同一个NavigationStack的外部叠加多个overlay挂载不同Sheet)

内容的提问来源于stack exchange,提问作者John Cashew

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 04:46:15