SwiftUI问题:视图状态变更时FocusState自动唤起键盘
解决SwiftUI视图切换错误状态时自动弹出键盘的问题
问题核心是视图状态切换到.error时,SwiftUI重新渲染对应视图分支,焦点状态被意外保留,导致键盘自动弹出。可以通过以下两种方式解决:
方法一:在错误状态视图分支中主动清除焦点
直接在.error对应的视图上添加onAppear,触发时清空焦点状态:
struct SignInUI: View { @State var email: String = "" @State var password: String = "" private enum Field: Int, CaseIterable { case username, password } @FocusState private var focusedField: Field? @StateObject var viewModel: SignInViewModel var body: some View { Group { switch viewModel.state { case .loading: ZStack { content ProgressView() } case .error: ZStack { content ErrorView() } // 进入错误状态时清空焦点,收起键盘 .onAppear { focusedField = nil } case .loaded: content } } } var content: some View { VStack { PasswordTextField(field: $password) .focused($focusedField, equals: .password) EmailTextField(field: $email) .focused($focusedField, equals: .username) ButtonView(text: "Sign In", action: { focusedField = nil viewModel.signIn(email: email, password: password) }) } } }
方法二:监听状态变化统一处理
如果需要在多个状态切换场景下处理焦点,可以用onChange监听viewModel.state的变化:
struct SignInUI: View { @State var email: String = "" @State var password: String = "" private enum Field: Int, CaseIterable { case username, password } @FocusState private var focusedField: Field? @StateObject var viewModel: SignInViewModel var body: some View { Group { switch viewModel.state { case .loading: ZStack { content ProgressView() } case .error: ZStack { content ErrorView() } case .loaded: content } } // 监听状态变化,进入错误状态时清空焦点 .onChange(of: viewModel.state) { newState in if newState == .error { focusedField = nil } } } var content: some View { VStack { PasswordTextField(field: $password) .focused($focusedField, equals: .password) EmailTextField(field: $email) .focused($focusedField, equals: .username) ButtonView(text: "Sign In", action: { focusedField = nil viewModel.signIn(email: email, password: password) }) } } }
原理说明
FocusState绑定的focusedField直接控制TextField的焦点状态,将其设为nil会让所有绑定的TextField失去焦点,系统会自动收起键盘。在视图切换到错误状态时主动触发这个操作,就能避免键盘意外弹出。
内容的提问来源于stack exchange,提问作者Marta Paniti
相关产品推荐
相关产品推荐

