iOS开发使用UIKeyInput自定义密码输入框

栏目: IOS · 发布时间: 5年前

内容简介:开发中很多地方都会遇到密码输入,这时候往往需要根据UI设计自定义。这里遵守遵守根据配置信息,以及当前文字输入,绘制自定义UI,这里讲绘制代码和一些基本代码写在一起,单独抽离成

开发中很多地方都会遇到密码输入,这时候往往需要根据UI设计自定义。这里遵守 UIKeyInput ,实现协议中的方法,让自定义View可以进行文字输入;再通过 func draw(_ rect: CGRect) 绘制现自定义UI;使用配置类来统一接口;使用代理来管理各种输入相关的事件。文章末尾有提供OC和Swift双语的 CLDemo 下载,这里讲解就使用Swift。

1.遵守 UIKeyInput 协议,实现文字输入

遵守 UIKeyInput 协议,实现协议中 - (BOOL)hasText- (void)insertText:(NSString *)text- (void)deleteBackward 这三个方法。这里方便阅读,单独抽离成为一个 extension

extension CLPasswordInputView: UIKeyInput {
    var hasText: Bool {
        return text.length > 0
    }
    
    func insertText(_ text: String) {
        if self.text.length < config.passwordNum {
            let cs = NSCharacterSet.init(charactersIn: "0123456789").inverted
            let string = text.components(separatedBy: cs).joined(separator: "")
            let basicTest = text == string
            if basicTest {
                self.text.append(text)
                delegate?.passwordInputViewDidChange(passwordInputView: self)
                if self.text.length == config.passwordNum {
                    delegate?.passwordInputViewCompleteInput(passwordInputView: self)
                }
                setNeedsDisplay()
            }
        }
    }
    
    func deleteBackward() {
        if text.length > 0 {
            text.deleteCharacters(in: NSRange(location: text.length - 1, length: 1))
            delegate?.passwordInputViewDidChange(passwordInputView: self)
        }
        delegate?.passwordInputViewDidDeleteBackward(passwordInputView: self)
        setNeedsDisplay()
    }
}
复制代码

2.重写 override func draw(_ rect: CGRect) ,绘制自定义UI

根据配置信息,以及当前文字输入,绘制自定义UI,这里讲绘制代码和一些基本代码写在一起,单独抽离成 extension

extension CLPasswordInputView {
    override func becomeFirstResponder() -> Bool {
        if !isShow {
            delegate?.passwordInputViewBeginInput(passwordInputView: self)
        }
        isShow = true;
        return super.becomeFirstResponder()
    }
    override func resignFirstResponder() -> Bool {
        if isShow {
            delegate?.passwordInputViewEndInput(passwordInputView: self)
        }
        isShow = false
        return super.resignFirstResponder()
    }
    var keyboardType: UIKeyboardType {
        get {
            return .numberPad
        }
        set {
            
        }
    }
    override var canBecomeFirstResponder: Bool {
        return true
    }
    override var canResignFirstResponder: Bool {
        return true
    }
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        super.touchesBegan(touches, with: event)
        if !isFirstResponder {
            _ = becomeFirstResponder()
        }
    }
    func updateWithConfig(config: ((CLPasswordInputViewConfigure) -> Void)?) -> Void {
        config?(self.config)
        backgroundColor = self.config.backgroundColor
        setNeedsDisplay()
    }
    override func layoutSubviews() {
        super.layoutSubviews()
        setNeedsDisplay()
    }
    override func draw(_ rect: CGRect) {
        let height = rect.size.height
        let width = rect.size.width
        let squareWidth = min(max(min(height, config.squareWidth), config.pointRadius * 4), height)
        let pointRadius = min(config.pointRadius, squareWidth * 0.5) * 0.8
        let middleSpace = CGFloat(width - CGFloat(config.passwordNum) * squareWidth) / CGFloat(CGFloat(config.passwordNum - 1) + config.spaceMultiple * 2)
        let leftSpace = middleSpace * config.spaceMultiple
        let y = (height - squareWidth) * 0.5
        
        let context = UIGraphicsGetCurrentContext()
        
        for i in 0 ..< config.passwordNum {
            context?.addRect(CGRect(x: leftSpace + CGFloat(i) * squareWidth + CGFloat(i) * middleSpace, y: y, width: squareWidth, height: squareWidth))
            context?.setLineWidth(1)
            context?.setStrokeColor(config.rectColor.cgColor)
            context?.setFillColor(config.rectBackgroundColor.cgColor)
        }
        context?.drawPath(using: .fillStroke)
        context?.setFillColor(config.pointColor.cgColor)
        
        for i in 0 ..< text.length {
            context?.addArc(center: CGPoint(x: leftSpace + CGFloat(i + 1) * squareWidth + CGFloat(i) * middleSpace - squareWidth * 0.5, y: y + squareWidth * 0.5), radius: pointRadius, startAngle: 0, endAngle: .pi * 2, clockwise: true)
            context?.drawPath(using: .fill)
        }
    }
}
复制代码

3.使用配置类,来统一接口,生成基本配置信息

自定义UI过程中,对于颜色,间隙,原点大小等,都需要留出接口,方便外部修改。一大堆属性,对于使用者而言,并不友好,因为他并不知道哪些属性是必须的,哪些是非必须的,为了让使用者方便使用,这里单独抽离出一个配置信息类,在内部实现基础配置,同时给出方法,让外部可以修改某些属性。

class CLPasswordInputViewConfigure: NSObject {
    ///密码的位数
    var passwordNum: UInt = 6
    ///边框正方形的大小
    var squareWidth: CGFloat = 50
    ///黑点的半径
    var pointRadius: CGFloat = 18 * 0.5
    ///边距相对中间间隙倍数
    var spaceMultiple: CGFloat = 5;
    ///黑点颜色
    var pointColor: UIColor = UIColor.black
    ///边框颜色
    var rectColor: UIColor = UIColor.lightGray
    ///输入框背景颜色
    var rectBackgroundColor: UIColor = UIColor.white
    ///控件背景颜色
    var backgroundColor: UIColor = UIColor.white
    
    class func defaultConfig() -> CLPasswordInputViewConfigure {
        let configure = CLPasswordInputViewConfigure()
        return configure
    }
}
复制代码

外部修改配置的方法,使用闭包,将基本配置回调到外部,同时在外部修改这些属性后,对内部UI进行刷新。

func updateWithConfig(config: ((CLPasswordInputViewConfigure) -> Void)?) -> Void {
        config?(self.config)
        backgroundColor = self.config.backgroundColor
        setNeedsDisplay()
    }
复制代码

4.使用代理来管理各种输入相关的事件

这里单独创建一个协议,管理各种输入事件,同时通过 extension 实现这些协议,这样外部就可以选择性的实现这些协议,而不是必须实现。

protocol CLPasswordInputViewDelegate {
    ///输入改变
    func passwordInputViewDidChange(passwordInputView:CLPasswordInputView) -> Void
    ///点击删除
    func passwordInputViewDidDeleteBackward(passwordInputView:CLPasswordInputView) -> Void
    ///输入完成
    func passwordInputViewCompleteInput(passwordInputView:CLPasswordInputView) -> Void
    ///开始输入
    func passwordInputViewBeginInput(passwordInputView:CLPasswordInputView) -> Void
    ///结束输入
    func passwordInputViewEndInput(passwordInputView:CLPasswordInputView) -> Void
}

extension CLPasswordInputViewDelegate {
    ///输入改变
    func passwordInputViewDidChange(passwordInputView:CLPasswordInputView) -> Void {
        
    }
    ///点击删除
    func passwordInputViewDidDeleteBackward(passwordInputView:CLPasswordInputView) -> Void {
        
    }
    ///输入完成
    func passwordInputViewCompleteInput(passwordInputView:CLPasswordInputView) -> Void {
        
    }
    ///开始输入
    func passwordInputViewBeginInput(passwordInputView:CLPasswordInputView) -> Void {
        
    }
    ///结束输入
    func passwordInputViewEndInput(passwordInputView:CLPasswordInputView) -> Void {
        
    }
}
复制代码

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Tagging

Tagging

Gene Smith / New Riders / 2007-12-27 / GBP 28.99

Tagging is fast becoming one of the primary ways people organize and manage digital information. Tagging complements traditional organizational tools like folders and search on users desktops as well ......一起来看看 《Tagging》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

MD5 加密
MD5 加密

MD5 加密工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换