使用FocusState实现TextField焦点切换功能失效问题排查
SwiftUI TextField 点击Next切换焦点不收起键盘问题修复
我有两个TextField,点击其中一个弹出键盘后,点击键盘上的Next按钮时,需要在不收起键盘的情况下切换至下一个TextField。尝试用FocusState实现但未生效,相关代码如下:
import SwiftUI enum placeholder { case email case password var description: String { return switch self { case .email: "email" case .password: "password" } } var nextControll: String { return switch self { case .email: "password" case .password: "email" } } } struct customTextField: View { var placeHolder: placeholder = .email @State var description: String = "" @FocusState var focusstate: String? var body: some View { TextField(placeHolder.description, text: $description) .padding(.horizontal, 20) .frame(width: 300, height: 50) .background { RoundedRectangle(cornerRadius: 12) .stroke(Color.gray, lineWidth: 2) } .focused($focusstate, equals: placeHolder.description) .onSubmit { focusstate = placeHolder.nextControll } .submitLabel(.next) } } struct TextFieldObservers: View { var placeholderView: placeholder? var body: some View { Group { customTextField(placeHolder: .email, description: "") customTextField(placeHolder: .password, description: "") } .padding(.horizontal, 30) } } #Preview { TextFieldObservers() }
问题分析
核心问题在于每个自定义TextField都维护了独立的@FocusState,焦点状态被隔离在子视图内部,两个TextField无法共享焦点上下文,导致点击Next后无法正确切换焦点。此外,子视图用@State管理输入文本的方式也不符合SwiftUI的数据流规范,应该由父视图统一管理输入内容。
修复方案
将焦点状态(@FocusState)提升到父视图中,子视图通过@FocusState.Binding接收共享的焦点状态,确保两个TextField使用同一个焦点上下文,同时修正文本绑定的传递逻辑。
修改后的完整代码
import SwiftUI enum Field: Hashable { case email case password } struct CustomTextField: View { let field: Field let placeholder: String @Binding var text: String @FocusState.Binding var focusState: Field? var body: some View { TextField(placeholder, text: $text) .padding(.horizontal, 20) .frame(width: 300, height: 50) .background { RoundedRectangle(cornerRadius: 12) .stroke(Color.gray, lineWidth: 2) } .focused($focusState, equals: field) .submitLabel(field == .email ? .next : .done) .onSubmit { // 邮箱框点击Next切换到密码框,密码框点击Done收起键盘 focusState = field == .email ? .password : nil } } } struct TextFieldObservers: View { @State private var emailText = "" @State private var passwordText = "" @FocusState private var focusState: Field? var body: some View { VStack(spacing: 20) { CustomTextField( field: .email, placeholder: "email", text: $emailText, focusState: $focusState ) CustomTextField( field: .password, placeholder: "password", text: $passwordText, focusState: $focusState ) } .padding(.horizontal, 30) } } #Preview { TextFieldObservers() }
关键修改点
- 重命名枚举为
Field并遵循Hashable协议,符合FocusState对值类型的要求 - 将@FocusState移至父视图
TextFieldObservers,子视图通过@FocusState.Binding绑定共享焦点状态 - 子视图输入文本改用
@Binding绑定到父视图的@State变量,统一管理输入内容 - 优化键盘提交按钮显示逻辑:邮箱框显示Next,密码框显示Done
- 修正焦点切换逻辑,密码框点击Done时自动收起键盘
内容的提问来源于stack exchange,提问作者Beast
相关产品推荐
相关产品推荐

