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

SwiftUI关闭sheet后如何更新前序视图?三层视图间事件怎么传递?

实现方案

三种方案各有适用场景,仅需要单次事件通知优先选方案1,需要同步状态选方案2,层级复杂多组件共享选方案3。

方案1:闭包回调(最轻量化,适合当前简单场景)

逐层传递点击回调闭包,不需要额外管理状态,实现成本最低:

struct FirstView: View {
    @State var openSecondView: Bool = false
    var body: some View {
        Button {
            openSecondView = true
        } label: {
            Text("Click here to show second view")
        }.sheet(isPresented: $openSecondView) {
            SecondView(
                bindSecondView: $openSecondView,
                onThirdViewButtonClick: {
                    // 这里就能监听到ThirdView的点击事件,写你的更新逻辑
                    print("ThirdView按钮被点击了,FirstView收到通知")
                }
            )
        }
    }
}

struct SecondView: View {
    @Binding var bindSecondView: Bool
    // 接收上层传的回调,再往下传给ThirdView
    var onThirdViewButtonClick: () -> Void
    
    var body: some View {
        Button {
            bindSecondView = false
        } label: {
            Text("Click here to dismiss sheet")
        }
        ThirdView(onButtonClick: onThirdViewButtonClick)
    }
}

struct ThirdView: View {
    // 定义点击回调属性
    var onButtonClick: () -> Void
    
    var body: some View {
        Button {
            // 点击时触发回调
            onButtonClick()
        } label: {
            Text("By clicking this button in third view, first view should know about this so I can do some updates in first view")
        }
    }
}

方案2:@Binding 逐层传递状态

如果点击后需要同时修改FirstView的某个状态值,可以直接把状态通过Binding逐层往下传:

struct FirstView: View {
    @State var openSecondView: Bool = false
    // 要被ThirdView修改的状态
    @State var thirdViewButtonClicked: Bool = false
    
    var body: some View {
        VStack {
            Text("ThirdView是否点击:\(thirdViewButtonClicked ? "是" : "否")")
            Button {
                openSecondView = true
            } label: {
                Text("Click here to show second view")
            }
        }
        .sheet(isPresented: $openSecondView) {
            SecondView(
                bindSecondView: $openSecondView,
                thirdViewButtonClicked: $thirdViewButtonClicked
            )
        }
    }
}

struct SecondView: View {
    @Binding var bindSecondView: Bool
    @Binding var thirdViewButtonClicked: Bool
    
    var body: some View {
        Button {
            bindSecondView = false
        } label: {
            Text("Click here to dismiss sheet")
        }
        ThirdView(buttonClicked: $thirdViewButtonClicked)
    }
}

struct ThirdView: View {
    @Binding var buttonClicked: Bool
    
    var body: some View {
        Button {
            buttonClicked = true
        } label: {
            Text("点击通知FirstView")
        }
    }
}

方案3:@EnvironmentObject 全局环境对象(适合层级深、多组件共享状态的场景)

如果你的视图层级超过3层,或者多个地方都需要监听这个事件,用环境对象避免逐层传递的麻烦:
首先定义ObservableObject类:

class ViewEventModel: ObservableObject {
    // 发布事件,所有监听的视图都能收到
    @Published var thirdViewButtonClicked = false
}

视图层实现代码:

struct FirstView: View {
    @State var openSecondView: Bool = false
    @StateObject private var eventModel = ViewEventModel()
    
    var body: some View {
        VStack {
            Text("ThirdView是否点击:\(eventModel.thirdViewButtonClicked ? "是" : "否")")
            Button {
                openSecondView = true
            } label: {
                Text("Click here to show second view")
            }
        }
        .sheet(isPresented: $openSecondView) {
            SecondView(bindSecondView: $openSecondView)
                .environmentObject(eventModel) // 注入环境对象,所有子视图都可以自动继承读取
        }
        // 监听状态变化触发逻辑
        .onChange(of: eventModel.thirdViewButtonClicked) { newValue in
            if newValue {
                print("收到ThirdView点击事件")
                // 执行你需要的更新逻辑
            }
        }
    }
}

struct SecondView: View {
    @Binding var bindSecondView: Bool
    
    var body: some View {
        Button {
            bindSecondView = false
        } label: {
            Text("Click here to dismiss sheet")
        }
        ThirdView()
        // 不需要手动传递,环境对象自动继承
    }
}

struct ThirdView: View {
    // 直接读取环境对象
    @EnvironmentObject var eventModel: ViewEventModel
    
    var body: some View {
        Button {
            eventModel.thirdViewButtonClicked = true
        } label: {
            Text("点击通知FirstView")
        }
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 22:36:06