簡體   English   中英

按下清除按鈕時如何自動上一個文本字段 swiftui

[英]How to automatically previous textfield when clear button press swiftui

我正在嘗試創建 OTP 屏幕,當用戶在第一個文本字段中輸入數字並且在 cursor 自動移動到下一個文本字段之后,我得到了它的功能,但是當用戶刪除當前文本字段中的文本時我被卡住了以及如何自動移動到上一個文本字段。

截屏:-

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM