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

使用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 00:35:00