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

SwiftUI中自定义按钮无法关闭Sheet的问题排查求助

SwiftUI Sheet 自定义关闭按钮无法生效的解决方案

问题分析

你的自定义XMarkButton使用@Environment(\.dismiss)无法关闭Sheet,仅能通过下滑关闭,核心原因有两个:

  • Sheet被附加到了ZStack底层的背景Color视图上,导致dismiss环境变量无法正确传递到Sheet内部的导航层级
  • 你使用了已废弃的NavigationView,在iOS 16+系统中可能导致环境变量传递异常

解决方案

方案1:修正Sheet的附加层级

将Sheet从背景Color上移到ZStack的顶层视图上,确保环境变量能正确传递:

修改HomeView的代码:

struct HomeView: View {
    
    @EnvironmentObject private var vm: HomeViewModel
    @State private var showPortfolio: Bool = false
    @State private var showPortfolioView: Bool = false
    
    var body: some View {
        ZStack {
            // Background layer
            Color.theme.background
                .ignoresSafeArea()
            
            VStack {
                homeHeader
                HomeStatsView(showPortfolio: $showPortfolio)
                
                SearchBarView(searchText: $vm.searchText)
                
                columnTitles
                
                if !showPortfolio {
                    allCoinsList
                    .transition(.move(edge: .leading))
                }
                if showPortfolio {
                    portfolioCoinsList
                        .transition(.move(edge: .trailing))
                }
                
                Spacer(minLength: 0)
            }
        }
        // 将Sheet附加到ZStack顶层
        .sheet(isPresented: $showPortfolioView) {
            PortfolioView()
                .environmentObject(vm)
        }
    }
}

方案2:替换废弃的NavigationView为NavigationStack

在iOS 16+中,NavigationView已被废弃,改用NavigationStack可以修复环境变量传递的问题,同时符合最新SwiftUI规范:

修改PortfolioView的代码:

struct PortfolioView: View {    
    var body: some View {
        // 替换NavigationView为NavigationStack
        NavigationStack {
            ScrollView {
                VStack(alignment: .leading, spacing: 0) {
                    Text("Portfolio")
                }
            }
            .navigationTitle("Edit Portfolio")
            .toolbar(content: {
                ToolbarItem(placement: .navigationBarLeading) {
                    XMarkButton()
                }
            })
        }
    }
}

方案3:手动传递关闭动作(兼容iOS 15及以下)

如果需要兼容旧系统,可以放弃环境变量,手动传递关闭闭包:

  1. 修改XMarkButton,接受自定义动作:
struct XMarkButton: View {
    let action: () -> Void
    
    var body: some View {
        Button(action: action, label: {
            Image(systemName: "xmark")
                .font(.headline)
        })
    }
}
  1. 修改PortfolioView,接收关闭闭包:
struct PortfolioView: View {
    let dismiss: () -> Void
    
    var body: some View {
        NavigationView {
            ScrollView {
                VStack(alignment: .leading, spacing: 0) {
                    Text("Portfolio")
                }
            }
            .navigationTitle("Edit Portfolio")
            .toolbar(content: {
                ToolbarItem(placement: .navigationBarLeading) {
                    XMarkButton(action: dismiss)
                }
            })
        }
    }
}
  1. 在HomeView中传递关闭动作:
.sheet(isPresented: $showPortfolioView) {
    PortfolioView(dismiss: { showPortfolioView = false })
        .environmentObject(vm)
}

验证效果

完成上述修改后,点击XMarkButton即可正常关闭Sheet,无需依赖下滑手势。

内容的提问来源于stack exchange,提问作者L.Strachotta

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 12:47:45