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

iOS16 SwiftUI弹窗关闭后键盘引发布局异常Bug及临时方案求助

iOS16 SwiftUI Sheet关闭后页面布局未同步更新的临时修复方案

在iOS16系统中使用SwiftUI开发时,会遇到这样的Bug:当Sheet弹窗内的TextField唤起键盘后,关闭弹窗时键盘虽正常消失,但原页面布局并未同步更新,出现布局错乱。

复现代码

struct Test: View {
    
    @State var isPresented: Bool = false
    @State var text: String = ""
    
    var body: some View {
        VStack{
            Button {
                isPresented.toggle()
            } label: {
                Text("PRESENT")
            }
        }
        .sheet(isPresented: $isPresented) {
            ZStack {
                Color.red
                VStack{
                    TextField("Test", text: $text)
                        .frame(height: 50, alignment: .center)
                    Spacer()
                    Rectangle()
                        .fill(Color.blue)
                        .frame(width:300, height: 50)
                }
            }
        }
    }
}

临时解决方案

以下是两种可行的临时修复方式,可用于Apple官方修复该Bug前过渡:

方案1:通过id强制视图重建

在主视图中添加一个触发刷新的状态变量,在Sheet关闭的onDismiss回调中切换该变量,并绑定到主视图的id上,通过id变化强制视图重建,同步布局:

struct Test: View {
    @State var isPresented: Bool = false
    @State var text: String = ""
    @State private var refreshFlag = false // 触发刷新的标记变量

    var body: some View {
        VStack{
            Button {
                isPresented.toggle()
            } label: {
                Text("PRESENT")
            }
        }
        .sheet(isPresented: $isPresented, onDismiss: {
            // 关闭Sheet时切换标记,触发视图重建
            refreshFlag.toggle()
        }) {
            ZStack {
                Color.red
                VStack{
                    TextField("Test", text: $text)
                        .frame(height: 50, alignment: .center)
                    Spacer()
                    Rectangle()
                        .fill(Color.blue)
                        .frame(width:300, height: 50)
                }
            }
        }
        .id(refreshFlag) // 绑定id,标记变化时重建视图
    }
}

方案2:延迟触发布局更新

利用DispatchQueue在Sheet关闭后延迟一小段时间,通过无意义的布局参数变化触发主视图更新,适合不想重建整个视图的场景:

struct Test: View {
    @State var isPresented: Bool = false
    @State var text: String = ""
    @State private var layoutTrigger = false

    var body: some View {
        VStack{
            Button {
                isPresented.toggle()
            } label: {
                Text("PRESENT")
            }
        }
        .padding(layoutTrigger ? 0 : 0) // 用无意义的padding变化触发布局
        .sheet(isPresented: $isPresented, onDismiss: {
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
                layoutTrigger.toggle()
                DispatchQueue.main.asyncAfter(deadline: .now() + 0.01) {
                    layoutTrigger.toggle()
                }
            }
        }) {
            ZStack {
                Color.red
                VStack{
                    TextField("Test", text: $text)
                        .frame(height: 50, alignment: .center)
                    Spacer()
                    Rectangle()
                        .fill(Color.blue)
                        .frame(width:300, height: 50)
                }
            }
        }
    }
}

说明

以上方案均为临时 workaround,待Apple官方修复iOS16的该SwiftUI Bug后,可移除相关代码恢复原实现。

内容的提问来源于stack exchange,提问作者Igor Ševtšenko

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 05:15:27