支付功能在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)")
}
}