SwiftUI 中的单位数字文本字段输入和自动焦点提前

问题描述 投票:0回答:1

我正在尝试创建一个简单的输入表单,让用户输入四位数的时钟时间 - hh:mm。我想对输入进行可靠的检查,以确保它是有效的时间,并且我想尽早防止错误(例如,您可以输入“21”作为 24 小时制时间的 hh 部分,但不能输入“” 26 英寸)。

我不想为此使用选择器——我发现它们在六十分钟中选择一个很麻烦。

我尝试创建四个文本字段,每个字段分别代表(时钟小时数字 1)、(时钟小时数字 2)、(时钟分钟数字 1)和(时钟分钟数字 2)。这些在下面的代码中显示为 ch1、ch2、cm1 和 cm2。

我在一个单独的线程中添加了数字输入检查,以确保 StackOverflow 上的数字输入干净。每次我获得一个好的数字时,我都想将焦点前进到序列中的下一个文本字段。

我设置了一个散列枚举来标识字段。它们是 f_ch1、f_ch2、f_cm1 和 f_cm2,对应于绑定到不同输入文本字段的数字。

验证工作正常。在验证器的“else”部分中,当我获得有效数字时,我尝试明确地将焦点设置到序列中的下一个字段。焦点确实离开了我当前所在的字段,但下一个字段不会自动获得键盘焦点。除此之外,当在我的 macbook pro 上的模拟器上运行时,调试器窗口报告:

-[RTIInputSystemClient remoteTextInputSessionWithID:performInputOperation:]执行输入操作需要有效的sessionID

我知道这很丑陋,有很多硬编码的基础设施。我很高兴简化,但首先想要真正理解这样的东西应该如何在 SwiftUI 下工作。我很高兴收到任何建议。特别欢迎示例代码;我是一名相当新的 Swift 开发人员,经常被 Apple 文档的简洁性所困扰。

以下是报名表的完整代码:

//
//  ContentView.swift
//  StackOverflowExample
//
//  Created by Mike Olson on 10/8/23.
//

import SwiftUI
import Combine

struct ContentView: View {
    
    // buch of hard-coded infra to automatically advance focus through the form
    enum Field: Hashable {
        case f_ch1
        case f_ch2
        case f_cm1
        case f_cm2
    }
    @FocusState private var focusedField: Field?

    // Clock digits
    @State private var ch1 = ""
    @State private var ch2 = ""
    @State private var cm1 = ""
    @State private var cm2 = ""

    var body: some View {
        VStack {
            HStack {
                TextField("h", text: $ch1)
                    .focusable(true, interactions: .edit)
                    .focused($focusedField, equals: .f_ch1)
                    .font(.title3)
                    .keyboardType(.numberPad)
                    .onReceive(Just(ch1)) { newValue in
                        let filtered = newValue.filter { "012".contains($0) } // first digit can be 0, 1, 2
                        if filtered != newValue {
                            self.ch1 = filtered
                        } else {
                            focusedField = .f_ch2
                        }
                    }
                TextField("h", text: $ch2)
                    .focusable(true, interactions: .edit)
                    .focused($focusedField, equals: .f_ch2)
                    .font(.title3)
                    .keyboardType(.numberPad)
                    .onReceive(Just(ch2)) { newValue in
                        let filtered = newValue.filter { (self.ch1 == "2" ? "0123" : "0123456789").contains($0) } // if the first digit's a 2, the second can't be bigger than 3
                        if filtered != newValue {
                            self.ch2 = filtered
                        } else {
                            focusedField = .f_cm1
                        }
                    }
                Text(":")
                    .font(.title3)
                TextField("m", text: $cm1)
                    .focusable(true, interactions: .edit)
                    .focused($focusedField, equals: .f_cm1)
                    .font(.title3)
                    .keyboardType(.numberPad)
                    .onReceive(Just(cm1)) { newValue in
                        let filtered = newValue.filter { "012345".contains($0) } // first minute digit is 0-5
                        if filtered != newValue {
                            self.cm1 = filtered
                        }
                    }
                TextField("m", text: $cm2)
                    .focusable(true, interactions: .edit)
                    .focused($focusedField, equals: .f_cm2)
                    .font(.title3)
                    .keyboardType(.numberPad)
                    .onReceive(Just(cm2)) { newValue in
                        let filtered = newValue.filter { "0123456789".contains($0) }
                        if filtered != newValue {
                            self.cm2 = filtered
                        }
                    }
            }
            .frame(maxWidth: 100)
        }
        .frame(width: 200, height: 200)
    }
}

#Preview {
    ContentView()
}

swiftui focus textfield
1个回答
0
投票

这是做一件简单事情的困难方法。我将在用户完成任何操作之前验证用户输入的完整时间字符串。

© www.soinside.com 2019 - 2024. All rights reserved.