需求:
如图:
思路:
视图层级:
最底层一个隐藏的UITextView,上面铺的Label
输入焦点在UITextView,监听UITextView的输入,给Label赋值
通过Label显示输入的文字使用CAShapeLayer绘制光标
通过光标的显示隐藏来控制光标的移动
基础动画控制光标闪动
坑点:
- 用户有可能不按顺序输入。如:
1234,此时输入光标移动到location=0来输入
- 用户有可能不按顺序删除。如:(支付宝注册就有此bug)
1234,此时输入光标移动到location=1来删除
- 从粘贴板粘贴进来不合法的验证码。
- 4、光标在退后台后,返回前台,光标动画不动了
代码实现与解决方案:
一、坑点1、2、3解决方案:
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
// 输入框已有的值
var inputText = textView.text ?? ""
if text.count == 0 { // 删除
if range.location != inputText.count - 1 { // 删除的不是最后一个
if inputText.count > 0 {
// 手动删除最后一位
textView.text.removeLast()
textViewDidChange(textView)
}
return false
}
}
if let tempRange = Range.init(range, in: inputText) {
// 拼接输入后的值
inputText = inputText.replacingCharacters(in: tempRange , with: text)
let isMeet = inputText.inputValuesMeetRule(integerCount: nil, decimalCount: 0)
if isMeet == false {
return isMeet
}
}
if inputText.count > inputTextNum {
return false
}
return true
}
二、坑点4解决方案:
NotificationCenter.default.addObserver(self, selector: #selector(becomeActive), name: NSNotification.Name.UIApplicationDidBecomeActive, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(enterBack), name: NSNotification.Name.UIApplicationDidEnterBackground, object: nil)
/// 去后台
@objc fileprivate func enterBack() {
// 移除动画
cursor.removeAnimation(forKey: "kOpacityAnimation")
}
/// 回前台
@objc fileprivate func becomeActive() {
// 重新添加动画
cursor.add(opacityAnimation, forKey: "kOpacityAnimation")
}