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

SwiftUI实现逐位自动移位自定义数字TextField问题求解

3位联动数字输入TextField组件移位/退格逻辑实现

场景与需求

  • 基于3个TextField搭建数字输入组件,从左到右排列为f3、f2、f1,f1为最右侧的首位输入位
  • 已实现空态覆盖层:所有输入框为空时,拦截f2、f3的点击交互,点击覆盖层自动聚焦f1
  • 待实现交互规则:
    • 正向输入:输入第1个字符保留在f1;输入第2个字符时,原f1字符移位到f2,新输入字符留在f1;按该规则逐位左移;输入第4个字符时,自动替换f3中已有字符,始终保留最新输入的3位内容
    • 退格逻辑:f1内容为空时按下删除键,f2字符自动回移到f1,f3字符自动回移到f2,逐位回退

现有代码的问题

原有实现仅处理了f1输入2位时向f2移位的单一场景,存在明显逻辑漏项:

  • 移位没有做级联传递,字符到f2后不会继续向f3移动,无法实现满3位后新输入替换f3内容的效果
  • 完全没有处理退格时的字符回移逻辑
  • 写死.disabled(f1.isEmpty)会导致f1被清空后,f2、f3直接锁死无法交互
  • 没有做输入内容过滤,用户输入非数字字符会直接导致逻辑错乱

可直接运行的修复代码

// 补全原有代码缺失的焦点枚举定义
enum Field: Hashable {
    case f1, f2, f3
}

struct TV1: View {
    @State var f1: String = ""
    @State var f2: String = ""
    @State var f3: String = ""
    @FocusState var ff: Field?
    
    func isFormEmpty() -> Bool {
        return f1.isEmpty && f2.isEmpty && f3.isEmpty
    }
    
    // 统一处理正向输入的级联移位
    private func handleInputShift() {
        // 过滤非数字字符,限制f1最多暂存2位内容
        f1 = String(f1.filter { $0.isNumber }.prefix(2))
        guard f1.count == 2 else { return }
        
        let movedChar = f1.removeFirst()
        if f2.isEmpty {
            f2 = String(movedChar)
        } else {
            let f2Moved = f2.removeFirst()
            f2 = String(movedChar)
            // f3无论是否有值,直接接收f2移位过来的内容,实现新输入替换最老字符的效果
            f3 = String(f2Moved)
        }
    }
    
    // 处理退格时的字符回移
    private func handleBackspace() {
        guard f1.isEmpty, !f2.isEmpty || !f3.isEmpty else { return }
        if !f2.isEmpty {
            f1 = String(f2.removeFirst())
            if !f3.isEmpty {
                f2 = String(f3.removeFirst())
            }
        }
    }
    
    var body: some View {
        HStack(spacing: 12) {
            TextField("3", text: $f3)
                .font(.headline.weight(.semibold))
                .keyboardType(.numberPad)
                .frame(width: 44, height: 44)
                .background(.ultraThinMaterial, in: RoundedRectangle(cornerRadius: 8, style: .continuous))
                .focused($ff, equals: .f3)
                .multilineTextAlignment(.center)
                // 仅全空状态下禁用高位输入框
                .disabled(isFormEmpty())
            
            TextField("2", text: $f2)
                .font(.headline.weight(.semibold))
                .keyboardType(.numberPad)
                .frame(width: 44, height: 44)
                .background(.ultraThinMaterial, in: RoundedRectangle(cornerRadius: 8, style: .continuous))
                .focused($ff, equals: .f2)
                .multilineTextAlignment(.center)
                .disabled(isFormEmpty())
                .onChange(of: f2) { _ in
                    // 高位框输入后自动拉回焦点到f1,保持连续输入体验
                    ff = .f1
                    handleInputShift()
                }
            
            TextField("1", text: $f1)
                .font(.headline.weight(.semibold))
                .keyboardType(.numberPad)
                .frame(width: 44, height: 44)
                .background(.ultraThinMaterial, in: RoundedRectangle(cornerRadius: 8, style: .continuous))
                .focused($ff, equals: .f1)
                .multilineTextAlignment(.center)
                .onChange(of: f1) { newValue in
                    // f1为空时检测到删除操作,触发回移
                    if newValue.isEmpty, f1.isEmpty {
                        handleBackspace()
                        return
                    }
                    f1 = String(f1.filter { $0.isNumber })
                    handleInputShift()
                }
        }
        .overlay (
            Color.primary
                .opacity(isFormEmpty() && ff == nil ? 0.01 : 0)
                .onTapGesture {
                    ff = .f1
                }
        )
        .onAppear {
            ff = .f1
        }
    }
}

逻辑验证说明

  • 依次输入1、2、3、4,最终输入框显示为2 3 4,最早输入的1被自动顶出,符合满位替换规则
  • 连续按删除键,字符会从f1开始逐位回退,直到所有输入框清空触发空态拦截
  • 输入过程中自动过滤非数字内容,不会因为输入字母、符号导致逻辑异常
  • 非空状态下可以手动点击f2、f3编辑内容,编辑后自动回到f1焦点,不打断连续输入流程

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 00:32:22