简体   繁体   中英

How to automatically previous textfield when clear button press swiftui

I am trying to create OTP screen and when the user entered the digit in the first text field and after cursor automatically move to next text field, thus functionality I got it, but I was stuck when the user removes the text in the current text field and how to automatically move to the previous text field.

ScreenShot:-

OTP屏幕

Code:-

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
        }
     }
}

Can someone please explain to me how to back automatically when click on clear button, I've tried to implement but no results yet.

Any help would be greatly appreciated.

Thanks in advance.

try it

        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)
        }
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM