SwiftUI:输入一个字符后,是否可以自动移动到下一个文本框?

6
我正在制作一个SwiftUI应用程序,在TextField中输入一个字母后,光标会自动移动到下一个TextField。 UI基本上就像这个
在Swift/IB中,似乎是通过委托和添加目标来完成的,就像这篇文章中所述:如何在Swift中自动切换到下一个UITextField
但是我找不到任何有关在SwiftUI中使用委托/目标的文档。
我尝试按照这篇文章的指示进行操作:SwiftUI TextField max length,但是这对我没有效果。设置.prefix(1)似乎没有任何影响。TextField仍然接受任意数量的字符,并且当移动到下一个TextField时,不会将输入的字符减少为只有第一个字符。
在当前状态下的SwiftUI中,是否可能在输入1个字符后自动转到下一个TextField
感谢您的帮助!

我认为你已经提到了你的第一个选择 - 使用 UIKit。不要仅仅关注于 UITextFields,创建一个带有所有文本字段(和逻辑)的 UIViewController 并使用 UIViewControllerRepresentable。是的,这是很多工作。我唯一的另一个想法是使用 Compose 并在其中添加逻辑来“指向”下一个文本框。不确定焦点,但同样,可能需要像使用视图控制器可表示性一样多的工作。 - user7014451
1
鉴于目前的情况,如果您需要在文本字段上使用“高级功能”,那么最好将UITextField包装在Representable中。毕竟,这似乎是“纯”SwiftUI TextField正在做的事情。您可以通过观察通知UITextField.textDidChangeNotification来看到这一点。您会发现它也适用于TextField,并且作为其对象,它将为您提供相关的UITextField - kontiki
谢谢你们两位的回复。希望SwiftUI将来能够解决这个问题! - dcvonb
这可能会有所帮助。https://www.hackingwithswift.com/forums/100-days-of-swiftui/jump-focus-between-a-series-of-textfields-pin-code-style-entry-widget/765 - Mikael Weiss
1个回答

3
在iOS 15中,可以使用FocusState来完成此操作。
import SwiftUI
///Sample usage
@available(iOS 15.0, *)
struct PinParentView: View {
    @State var pin: Int = 12356
    var body: some View {
        VStack{
            Text(pin.description)
            PinView(pin: $pin)
        }
    }
}
@available(iOS 15.0, *)
struct PinView: View {
    @Binding var pin: Int
    @State var pinDict: [UniqueCharacter] = []
    @FocusState private var focusedField: UniqueCharacter?
    var body: some View{
        HStack{
            ForEach($pinDict, id: \.id, content: { $char in
                TextField("pin digit", text:
                            Binding(get: {
                    char.char.description
                }, set: { newValue in
                    let newest: Character = newValue.last  ?? "0"
                    //This check is only needed if you only want numbers
                    if Int(newest.description) != nil{
                        char.char = newest
                    }
                    //Set the new focus
                    DispatchQueue.main.async {
                        setFocus()
                    }
                })
                ).textFieldStyle(.roundedBorder)
                    .focused($focusedField, equals: char)
            })
            
        }.onAppear(perform: {
            //Set the initial value of the text fields
            //By using unique characters you can keep the order
            pinDict = pin.description.uniqueCharacters()
            
        })
    }
    func setFocus(){
        //Default to the first box when focus is not set or the user reaches the last box
        if focusedField == nil || focusedField == pinDict.last{
            focusedField = pinDict.first
        }else{
            //find the index of the current character
            let idx = pinDict.firstIndex(of: focusedField!)
            //Another safety check for the index
            if idx == nil || pinDict.last == pinDict[idx!]{
                focusedField = pinDict.first
            }else{
                focusedField = pinDict[idx! + 1]
            }
        }
        //Update the Binding that came from the parent
        setPinBinding()
    }
    ///Updates the binding from the parent
    func setPinBinding(){
        var newPinInt = 0
        for n in pinDict{
            if n == pinDict.first{
                newPinInt = Int(n.char.description) ?? 0
            }else{
                newPinInt = Int(String(newPinInt) + n.char.description) ?? 0
            }
        }
        pin = newPinInt
    }
}


//Convert String to Unique characers
extension String{
    func uniqueCharacters() -> [UniqueCharacter]{
        let array: [Character] = Array(self)
        return array.uniqueCharacters()
    }
    func numberOnly() -> String {
        self.trimmingCharacters(in: CharacterSet(charactersIn: "-0123456789.").inverted)
    }
    
}
extension Array where Element == Character {
    
    func uniqueCharacters() -> [UniqueCharacter]{
        var array: [UniqueCharacter] = []
        
        for char in self{
            array.append(UniqueCharacter(char: char))
        }
        return array
    }
    
}

//String/Characters can be repeating so yu have to make them a unique value
struct UniqueCharacter: Identifiable, Equatable, Hashable{
    var char: Character
    var id: UUID = UUID()
}

@available(iOS 15.0, *)
struct PinView_Previews: PreviewProvider {
    static var previews: some View {
        PinParentView()
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接