Swift 使用UIKeyInput实现支付密码输入框的效果

支付功能在App中是比较常见的功能, 如何实现一个类似于微信密码支付框的功能呢, 其实很简单, 只需要让自定义View实现UIKeyInput协议即可, UIKeyInput可以为响应者提供简单的键盘输入功能, 让需要键盘的UIResponder成为第一响应者:

实现效果如下(颜色搭配很丑, 请自动忽略,如果想改变圆点样式,请自己添加属性):

1.png

UIKeyInput有一个属性及两个方法(翻译的不是很准确, 请见谅):

public var hasText:Bool { get } //文本输入对象是否有内容

public func insertText(_text: String) //文本输入对象插入文本时调用

public func deleteBackward() //删除文本输入对象中的文本时调用

自定义密码框视图(如果有写的不对的地方, 欢迎大家批评指正):

import UIKit
//文本内容发生改变时调用
@objc protocol PasswordViewDelegate {
    //文本发生改变(插入或删除)时调用
    @objc optional func passwordView(textChanged: String, length: Int)
    
    //输入完成(输入的长度与指定的密码最大长度相同)时调用
    func passwordView(textFinished: String)
}

class PasswordView: UIView, UIKeyInput {
    //输入的文本
    private var text: NSMutableString = ""
    
    //文本发生改变时的代理
    var delegate: PasswordViewDelegate?
    
    //密码最大长度
    var maxLength: Int = 6
    
    var hasText: Bool {
        return text.length > 0
    }
    
    func insertText(_ text: String) {
        if self.text.length < maxLength {
            self.text.append(text)
            delegate?.passwordView?(textChanged: self.text as String, length: self.text.length)
            setNeedsDisplay()
            if self.text.length == maxLength {
                self.resignFirstResponder()
                delegate?.passwordView(textFinished: self.text as String)
            }
        }
    }
    
    func deleteBackward() {
        if self.text.length > 0 {
            self.text.deleteCharacters(in: NSRange(location: text.length - 1, length: 1))
            delegate?.passwordView?(textChanged: self.text as String, length: self.text.length)
            setNeedsDisplay()
        }
    }
    
    override func draw(_ rect: CGRect) {
        guard let context = UIGraphicsGetCurrentContext() else { return }
        let width = rect.width / CGFloat(maxLength) //每一个小格子的宽度
        context.setStrokeColor(UIColor.green.cgColor)
        context.setLineWidth(1)
        //外边框
        context.stroke(rect)
        let path = UIBezierPath()
        //画中间分隔的竖线
        (1..<maxLength).forEach { (index) in
            path.move(to: CGPoint(x: rect.origin.x + CGFloat(index) * width, y: rect.origin.y))
            path.addLine(to: CGPoint(x: rect.origin.x + CGFloat(index) * width, y: rect.origin.y + rect.height))
        }
        context.addPath(path.cgPath)
        context.strokePath()
        //画圓点
        let pointSize = CGSize(width: width * 0.3, height: width * 0.3)
        (0..<self.text.length).forEach { (index) in
            let origin = CGPoint(x: rect.origin.x + CGFloat(index) * width + (width - pointSize.width) / 2, y: rect.origin.y + (rect.height - pointSize.height) / 2)
            let pointRect = CGRect(origin: origin, size: pointSize)
            context.fillEllipse(in: pointRect)
        }
    }
    
    //键盘的样式 (UITextInputTraits中的属性)
    var keyboardType: UIKeyboardType {
        get{
            return .numberPad
        } set{
            
        }
    }
    
    override var canBecomeFirstResponder: Bool {
        return true
    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        if !isFirstResponder {
            becomeFirstResponder()
        }
    }
}

使用自定义视图

class ViewController: UIViewController {
    private var passwordView: PasswordView!
    override func viewDidLoad() {
        super.viewDidLoad()
        passwordView = PasswordView(frame: CGRect(x: 0, y: 0, width: 300, height: 60))
        passwordView.center = view.center
        passwordView.backgroundColor = UIColor.lightGray
        passwordView.delegate = self
        passwordView.maxLength = 6
        view.addSubview(passwordView)
    }
    
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        if passwordView.isFirstResponder {
            passwordView.resignFirstResponder()
        }
    }
}

extension ViewController: PasswordViewDelegate {
    func passwordView(textFinished: String) {
        print("输入完成: \(textFinished)")
    }
    
    func passwordView(textChanged: String, length: Int) {
        print("文本改变: \(textChanged), length: \(length)")
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容