前言

开发中很多地方都会遇到密码输入,这时候往往需要根据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").invertedlet string = text.components(separatedBy: cs).joined(separator: "")let basicTest = text == stringif 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 = falsereturn 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.backgroundColorsetNeedsDisplay()}override func layoutSubviews() {super.layoutSubviews()setNeedsDisplay()}override func draw(_ rect: CGRect) {let height = rect.size.heightlet width = rect.size.widthlet squareWidth = min(max(min(height, config.squareWidth), config.pointRadius * 4), height)let pointRadius = min(config.pointRadius, squareWidth * 0.5) * 0.8let middleSpace = CGFloat(width - CGFloat(config.passwordNum) * squareWidth) / CGFloat(CGFloat(config.passwordNum - 1) + config.spaceMultiple * 2)let leftSpace = middleSpace * config.spaceMultiplelet y = (height - squareWidth) * 0.5let 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.whiteclass func defaultConfig() -> CLPasswordInputViewConfigure {let configure = CLPasswordInputViewConfigure()return configure}
}
复制代码

外部修改配置的方法,使用闭包,将基本配置回调到外部,同时在外部修改这些属性后,对内部UI进行刷新,这里block是局部变量,不会循环引用。

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

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

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

protocol CLPasswordInputViewDelegate: class {///输入改变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 {}
}
复制代码

5.效果图

这里简单录制了一个效果,更多请参考CLDemo

6.总结

为了方便大家学习,这里提供了OC和Swift两种语言分别实现的----->>>CLDemo,如果对你有所帮助,欢迎Star。

iOS开发使用UIKeyInput自定义密码输入框相关推荐

  1. iOS开发多线程篇—自定义NSOperation

    iOS开发多线程篇-自定义NSOperation 一.实现一个简单的tableView显示效果 实现效果展示: 代码示例(使用以前在主控制器中进行业务处理的方式) 1.新建一个项目,让控制器继承自UI ...

  2. iOS开发那些事--自定义单元格实现

    自定义单元格 当苹果公司提供给的单元格样式不能我们的业务需求的时候,我们需要自定义单元格.在iOS 5之前,自定义单元格可以有两种实现方式:代码实现和用xib技术实现.用xib技术实现相对比较简单,创 ...

  3. iOS开发小结 - 使用自定义字体

    APP开发过程中,根据美工的需求可能会用到一些特殊的字体,然而在苹果自带字体中并没有,那就必须我们开发来来实现这些功能呢,下面以冬青黑体简体中文(Hiragino Sans GB)为例子给大家演示一下 ...

  4. iOS开发学无止境 - UICollectionView自定义布局之风火轮[译]

    现在有许多极具创造力的网站,几周前我碰巧浏览到一个名为Form Follows Function的网站,上面有各种交互动画.其中最吸引我的是网站上的导航转轮,转轮由各种交互体验海报组成. 原文:UIC ...

  5. iOS开发总结-UITableView 自定义cell和动态计算cell的高度

    UITableView cell自定义头文件: shopCell.h #import <UIKit/UIKit.h> @interface shopCell : UITableViewCe ...

  6. 文顶顶iOS开发博客链接整理及部分项目源代码下载

    网上的iOS开发的教程很多,但是像cnblogs博主文顶顶的博客这样内容图文并茂,代码齐全,示例经典,原理也有阐述,覆盖面宽广,自成系统的系列教程却很难找.如果你是初学者,在学习了斯坦福iOS7公开课 ...

  7. iOS开发之自定义View的一些坑

    我们做几个简单的例子哈 自定义一个View View的m文件中有代码如下: @implementation BMView- (instancetype)init {if (self = [super ...

  8. iOS开发之窥探UICollectionViewController(四) --一款功能强大的自定义瀑布流

    在上一篇博客中<iOS开发之窥探UICollectionViewController(三) --使用UICollectionView自定义瀑布流>,自定义瀑布流的列数,Cell的外边距,C ...

  9. IOS开发之自定义UIActionSheet

    IOS开发中,经常会用到UIActionSheet,但是,默认的只能添加按钮.如果能自定义的话,岂不是更好?上网搜了一下,都是只有那一种代码,通过设置几个按钮来增加UIActionSheet的高度,不 ...

最新文章

  1. R语言stringr包str_dup函数字符串多次复制实战
  2. 洛谷P1157----组合数的输出
  3. JVM用户自定义加载器实现步骤
  4. WPF 记一个Popup踩坑记录
  5. Java中带有JWebSocket的WebServerSocket
  6. vue性能优化-------vendor优化详细用法(瘦身),减小体积,引入cdn
  7. 多进程服务器(python 版)
  8. 分布式session的6种解决方案
  9. HighChat动态绑定数据 数据后台绑定(三)
  10. 机器学习经典算法笔记——线性回归
  11. 开源面临生死存亡之际!
  12. Hive启动的三种方式
  13. 白盒测试实践作业进度报告——Day 3
  14. 啊哈C语言-20220823学习练习
  15. stm32 SWD printf SWD调试输出
  16. CentOS Steam 9 安装测试
  17. web服务器利用线程响应http请求,多线程实现的HTTP应用服务器(HTTPWebServer)Mutu 0.2 alpha连载I...
  18. 大话Linux之 跟我走吧,现在就出发[2]Linux我想和你在一起(2)Vim,vim,I love you!有图有真相!
  19. php mysql多线程处理数据6_PHP WIN MYSQL Rdeis 下多进程处理产品数据测试 31 万条 6 进程...
  20. 生产者消费者模式解决强耦合问题

热门文章

  1. 关于vue2用vue-cli搭建环境后域名代理的http-proxy-middleware解决api接口跨域问题
  2. 源码安装php时出现configure: error: xml2-config not found. Please check your libxml2 installation...
  3. 让网站和APP更具动感的几点建议
  4. [Android自定义控件] Android Scroller工具类和GestureDetector的简单用法
  5. Cerberus 银行木马开发团队解散,源代码5万美元起拍
  6. Java EE之JSP
  7. 4.8 定位一组元素
  8. 当把CocoaPods生成的workspace移动到上层目录时
  9. 《人工智能:计算Agent基础》——1.5 复杂性维度
  10. Mysql经常使用函数汇总