清除按钮按下swiftui时如何自动上一个文本字段

How to automatically previous textfield when clear button press swiftui

我正在尝试创建 OTP 屏幕,当用户在第一个文本字段中输入数字并且光标自动移动到下一个文本字段后,我得到了它的功能,但是当用户删除文本时我被卡住了在当前文本字段中以及如何自动移动到上一个文本字段。

截图:-

代码:-

import SwiftUI

struct VerficationCode: View {
@State private var numberOfCells: Int = 6
@State private var currentlySelectedCell = 0

var body: some View {
    HStack {
        Group {
            ForEach(0 ..< self.numberOfCells) { index in
                CharacterInputCell(currentlySelectedCell: self.$currentlySelectedCell, index: index)
            }
        }.frame(width:15,height: 56)
        .padding(.horizontal)
        .foregroundColor(.white)
        .cornerRadius(10)
        .keyboardType(.numberPad)
       }
    }
 }

struct CharacterInputCell: View {
@State private var textValue: String = ""
@Binding var currentlySelectedCell: Int

var index: Int

var responder: Bool {
    return index == currentlySelectedCell
}

var body: some View {
    CustomTextField(text: $textValue, currentlySelectedCell: $currentlySelectedCell, isFirstResponder: responder)
    }
 }

   struct CustomTextField: UIViewRepresentable {

class Coordinator: NSObject, UITextFieldDelegate {
    
    @Binding var text: String
    @Binding var currentlySelectedCell: Int
    
    var didBecomeFirstResponder = false
    
    init(text: Binding<String>, currentlySelectedCell: Binding<Int>) {
        _text = text
        _currentlySelectedCell = currentlySelectedCell
    }
    
    func textFieldDidChangeSelection(_ textField: UITextField) {
        DispatchQueue.main.async {
            self.text = textField.text ?? ""
        }
    }
    
    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        let currentText = textField.text ?? ""
        guard let stringRange = Range(range, in: currentText) else { return false }
        let updatedText = currentText.replacingCharacters(in: stringRange, with: string)
        if updatedText.count <= 1 {
            self.currentlySelectedCell += 1
        }
        return updatedText.count <= 1
    }
}

@Binding var text: String
@Binding var currentlySelectedCell: Int
var isFirstResponder: Bool = false

func makeUIView(context: UIViewRepresentableContext<CustomTextField>) -> UITextField {
    let textField = UITextField(frame: .zero)
    textField.delegate = context.coordinator
    textField.textAlignment = .center
    textField.keyboardType = .decimalPad
    return textField
}

func makeCoordinator() -> CustomTextField.Coordinator {
    return Coordinator(text: $text, currentlySelectedCell: $currentlySelectedCell)
}

func updateUIView(_ uiView: UITextField, context: UIViewRepresentableContext<CustomTextField>) {
    uiView.text = text
    if isFirstResponder && !context.coordinator.didBecomeFirstResponder  {
        uiView.becomeFirstResponder()
        context.coordinator.didBecomeFirstResponder = true
        }
     }
}

谁能告诉我点击清除按钮时如何自动返回,我已经尝试实现但还没有结果。

如有任何帮助,我们将不胜感激。

提前致谢。

试一试

        import SwiftUI
    public struct PasscodeField: View {
        
        var maxDigits: Int = 6
        var label = "Enter One Time Password"
        
        @State var pin: String = ""
        @State var showPin = true
        //@State var isDisabled = false
        
        
        var handler: (String, (Bool) -> Void) -> Void
        
        public var body: some View {
            VStack{
                Text(label).font(.title)
                ZStack {
                    pinDots
                    backgroundField
                }
                showPinStack
            }
            
        }
        
        private var pinDots: some View {
            HStack {
                Spacer()
                ForEach(0..<maxDigits) { index in
                    Image(systemName: self.getImageName(at: index))
                        .font(.system(size: 60))
                    Spacer()
                }.frame(minWidth: 0, maxWidth: .infinity)
                .padding(.trailing, -24)
            }
        }
        
        private var backgroundField: some View {
            let boundPin = Binding<String>(get: { self.pin }, set: { newValue in
                self.pin = newValue
                self.submitPin()
            })
            
            return TextField("", text: boundPin, onCommit: submitPin)
          
          // Introspect library can used to make the textField become first resonder on appearing
          // if you decide to add the pod 'Introspect' and import it, comment #50 to #53 and uncomment #55 to #61
          
               .accentColor(.clear)
               .foregroundColor(.clear)
               .keyboardType(.numberPad)
               //.disabled(isDisabled)
          
    //             .introspectTextField { textField in
    //                 textField.tintColor = .clear
    //                 textField.textColor = .clear
    //                 textField.keyboardType = .numberPad
    //                 textField.becomeFirstResponder()
    //                 textField.isEnabled = !self.isDisabled
    //         }
        }
        
        private var showPinStack: some View {
            HStack {
                Spacer()
                if !pin.isEmpty {
                    showPinButton
                }
            }
            .frame(height: 100)
            .padding([.trailing])
        }
        
        private var showPinButton: some View {
            Button(action: {
                self.showPin.toggle()
            }, label: {
                self.showPin ?
                    Image(systemName: "eye.slash.fill").foregroundColor(.primary) :
                    Image(systemName: "eye.fill").foregroundColor(.primary)
            })
        }
        
        private func submitPin() {
            //guard !pin.isEmpty else {
                //showPin = false
                //return
            //}
            
            if pin.count == maxDigits {
                //isDisabled = true
                
                handler(pin) { isSuccess in
                    if isSuccess {
                        print("pin matched, go to next page, no action to perfrom here")
                    } else {
                        pin = ""
                        //isDisabled = false
                        print("this has to called after showing toast why is the failure")
                    }
                }
            }
            
            // this code is never reached under  normal circumstances. If the user pastes a text with count higher than the
            // max digits, we remove the additional characters and make a recursive call.
            if pin.count > maxDigits {
                pin = String(pin.prefix(maxDigits))
                submitPin()
            }
        }
        
        private func getImageName(at index: Int) -> String {
            if index >= self.pin.count {
                return "circle"
            }
            
            if self.showPin {
                return self.pin.digits[index].numberString + ".circle"
            }
            
            return "circle.fill"
        }
    }

    extension String {
        
        var digits: [Int] {
            var result = [Int]()
            
            for char in self {
                if let number = Int(String(char)) {
                    result.append(number)
                }
            }
            
            return result
        }
        
    }

    extension Int {
        
        var numberString: String {
            
            guard self < 10 else { return "0" }
            
            return String(self)
        }
    }