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

SwiftUI:TabView与NavigationStack嵌套时Sheet内TextField后台重置问题

问题原因与解决方法

问题原因

SwiftUI中,@State是绑定到视图自身的状态存储,当视图被销毁并重新创建时,@State会自动重置为初始值。在TabView+NavigationStack的组合结构下,应用前后台切换时,系统可能触发视图层级的重新计算,导致FormView所在的sheet内容被销毁后重建——由于FormView的输入状态是自身持有的@State,重建后自然丢失之前的输入内容。

而Form 2的输入状态存在父视图ContentView的@State里,父视图在前后台切换时不会被销毁,因此状态能稳定保留。另外,移除TabView或NavigationStack任意一个组件后,视图层级的稳定性提升,sheet的内容不会被触发重建,状态也就不会丢失。

解决方法

方法1:将状态提升到父视图(适合简单场景)

把FormView的输入状态移到父视图,通过绑定传递给子视图,让状态的生命周期和父视图绑定,不受子视图重建影响:

struct ContentView: View {
    @State var isShowingForm1 = false
    @State var isShowingForm2 = false
    @State var email = ""
    @State var password = ""

    var body: some View {
        TabView {
            NavigationStack {
                List {
                    Button("Form 1") {
                        isShowingForm1 = true
                    }
                    .sheet(isPresented: $isShowingForm1) {
                        FormView(email: $email, password: $password)
                            .padding()
                    }

                    Button("Form 2") {
                        isShowingForm2 = true
                    }
                    .sheet(isPresented: $isShowingForm2) {
                        VStack {
                            TextField("Email", text: $email)
                            SecureField("Password", text: $password)
                        }
                        .padding()
                    }
                }
            }
            .tabItem {
                Label("Tab1", systemImage: "circle")
            }
        }
    }
}

struct FormView: View {
    @Binding var email: String
    @Binding var password: String

    var body: some View {
        VStack {
            TextField("Email", text: $email)
            SecureField("Password", text: $password)
        }
    }
}

方法2:使用@StateObject管理子视图状态(适合复杂子视图)

如果希望状态由FormView自身管理,可以用@StateObject存储状态——@StateObject的生命周期独立于视图重建,只要视图没有被完全移除,状态对象就会保留:

class FormViewModel: ObservableObject {
    @Published var email = ""
    @Published var password = ""
}

struct ContentView: View {
    @State var isShowingForm1 = false
    @State var isShowingForm2 = false
    @State var email = ""
    @State var password = ""

    var body: some View {
        TabView {
            NavigationStack {
                List {
                    Button("Form 1") {
                        isShowingForm1 = true
                    }
                    .sheet(isPresented: $isShowingForm1) {
                        FormView()
                            .padding()
                    }

                    Button("Form 2") {
                        isShowingForm2 = true
                    }
                    .sheet(isPresented: $isShowingForm2) {
                        VStack {
                            TextField("Email", text: $email)
                            SecureField("Password", text: $password)
                        }
                        .padding()
                    }
                }
            }
            .tabItem {
                Label("Tab1", systemImage: "circle")
            }
        }
    }
}

struct FormView: View {
    @StateObject private var viewModel = FormViewModel()

    var body: some View {
        VStack {
            TextField("Email", text: $viewModel.email)
            SecureField("Password", text: $viewModel.password)
        }
    }
}

方法3:调整sheet的挂载层级

把sheet从List的Button上移到更上层的视图(比如NavigationStack),减少因List行重建导致的sheet内容重置:

struct ContentView: View {
    @State var isShowingForm1 = false
    @State var isShowingForm2 = false
    @State var email = ""
    @State var password = ""

    var body: some View {
        TabView {
            NavigationStack {
                List {
                    Button("Form 1") {
                        isShowingForm1 = true
                    }

                    Button("Form 2") {
                        isShowingForm2 = true
                    }
                }
                .sheet(isPresented: $isShowingForm1) {
                    FormView()
                        .padding()
                }
                .sheet(isPresented: $isShowingForm2) {
                    VStack {
                        TextField("Email", text: $email)
                        SecureField("Password", text: $password)
                    }
                    .padding()
                }
            }
            .tabItem {
                Label("Tab1", systemImage: "circle")
            }
        }
    }
}

struct FormView: View {
    @State var email = ""
    @State var password = ""

    var body: some View {
        VStack {
            TextField("Email", text: $email)
            SecureField("Password", text: $password)
        }
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 04:07:32