美文网首页
SwiftUI Pin 输入的验证码字段

SwiftUI Pin 输入的验证码字段

作者: Bepawbikvy | 来源:发表于2021-07-08 09:23 被阅读0次
    实现效果:
    image.png
    实现原理:

    将一个TextTextFileld添加到ZStack相同的位置,TextFileldZ轴上的元素textField设置clear颜色

    ZStack {
       pinDots
       backgroundField
    }
    // 
    return TextField("", text: boundPin, onCommit: submitPin)
         .accentColor(.clear)
         .foregroundColor(.clear)
         .keyboardType(.numberPad)
    

    与 数量相等的图像(maxDigits默认为 4)位于 a 内HStack。根据用户输入的字符数,我们显示圆形边框或实心圆圈。点击showPin看起来像眼睛的按钮,将显示用户输入的数字。

    没有delegate得到变化的用户类型textField。因此,我们正在使用Binding<String>. 即使这整个PasscodeField是一种解决方法。如果 Apple 提供了符合TextFieldStyle 协议的正确方法,则可能不需要这些。ButtonStyleToggleStyle协议非常酷,让生活更轻松。

    现在让我们回到代码。每次值改变时,我们调用一个方法并检查用户是否输入了最大位数。如果是,我们禁用textField并调用完成处理程序块。

    private func submitPin() {
            if pin.count > maxDigits {
                // 如果超出长度就忽略本次输入
                pin = String(pin.prefix(maxDigits))
            } else if pin.count == maxDigits {
                // 验证
                handler(pin) { isSuccess in
                    if isSuccess {
                        logger.debug("pin matched, go to next page, no action to perfrom here")
                    } else {
                        pin = ""
                        logger.debug("this has to called after showing toast why is the failure")
                    }
                }
            }
        }
    
    如何调用:
    CaptchaView(maxDigits: 6, pin: .constant("6"), showPin: true) { strng, reponsetrue in
            }
    

    完整代码:
    import SwiftUI
    
    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)
       }
    }
    
    struct CaptchaView: View {
        var maxDigits: Int = 6
        @Binding var pin: String
        @State var showPin = true
        var handler: (String, (Bool) -> Void) -> Void
        
        var body: some View {
            VStack {
                ZStack {
                    pinDots
                    backgroundField
                }
            }
        }
        
        private var pinDots: some View {
            HStack {
                ForEach(0..<maxDigits) { index in
                    Text(self.getNumber(at: index))
                        .font(.system(size: 24).weight(.bold))
                        .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: 50, alignment: .center)
                        .padding(EdgeInsets(top: 7, leading: 0, bottom: 7, trailing: 0))
                        .border((index == self.pin.count) ? Color.OasisThemeColor : Color.OasisDisableColor, width: 0.5)
                }
            }
        }
        private func getNumber(at index: Int) -> String {
            
            if index == self.pin.count {
                return "_"
            }
            if index >= self.pin.count {
                return " "
            }
            if self.pin.count > maxDigits {
                self.showPin = false
            }
            if self.showPin {
                return self.pin.digits[index].numberString
            }
            return " "
        }
        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)
                .accentColor(.clear)
                .foregroundColor(.clear)
                .keyboardType(.numberPad)
        }
        private func submitPin() {
            if pin.count > maxDigits {
                // 如果超出长度就忽略本次输入
                pin = String(pin.prefix(maxDigits))
            } else if pin.count == maxDigits {
                // 验证
                handler(pin) { isSuccess in
                    if isSuccess {
                        logger.debug("pin matched, go to next page, no action to perfrom here")
                    } else {
                        pin = ""
                        logger.debug("this has to called after showing toast why is the failure")
                      }
                   }
                }
            }
    }
    

    参考:SwiftUI — Passcode field for OTP and Pin entry

    相关文章

      网友评论

          本文标题:SwiftUI Pin 输入的验证码字段

          本文链接:https://www.haomeiwen.com/subject/fvrsultx.html