当我们在项目中有支付场景的时候,系统键盘可能有时候满足不了我们的需求了,这时候就需要我们自己来封装支付键盘,并添加一些逻辑校验,以保证良好的用户体验。
这是给键盘加的一些规则:
① 首位输入0后,不可继续输入整数,可输入小数点及小数点后两位
② 首位不可输入小数点,若有小数点,小数点后最多可输入两位数
③ 最多可输入9位整数,之后可输入小数点,不可再输入整数
④ 光标移动删除小数点,若小数点前只有整数0,则不能删除,若是非0整数则删除小数点,保留小数点后两位数
⑤ 长按删除键,可连续删除
界面大概是这样的:
下面直接贴代码,封装了一个键盘工具类,可以拿来直接用:
//
// NumberKeyboard.swift
// JiuLiFunds
//
// Created by yangyunfei on 2018/1/5.
// Copyright © 2018年 JiuLiFunds. All rights reserved.
//
//封装 浮点数 数字键盘
import UIKit
class NumberKeyboard: UIView {
let baseTag = 1000
weak var firstResponder:UITextField?
var deleteTimer:Timer?
var done: (() -> Void)? /*< 点击确定执行的回调 */
override init(frame:CGRect) {
let rect =makeRect(x: 0, y:0, width: kScreenWidth * BiLi_SCREENWIDTH_NORMAL, height:200 * BiLi_SCREENHEIGHT_NORMAL)
super.init(frame: rect)
createUI()
}
required init?(coder aDecoder:NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func createUI() {
self.backgroundColor =UIColor.hexToUIColor(sourceString:"dddddd")
for i in0..<14 {
let btn = UIButton(type: .custom)
btn.backgroundColor = WHITECOLOR
//设置高亮时按钮背景颜色
btn.setBackgroundImage(UIImage.imageWithColor(color:UIColor.hexToUIColor(sourceString:"e5e5e5")), for: .highlighted)
switch i {
case 10://小数点
btn.tag = baseTag + i
btn.titleLabel?.font =FONT24
btn.setTitleColor(TITLTEXTECOLOR, for: .normal)
btn.setTitle(".", for: .normal)
case 11://键盘
btn.tag = baseTag + i
btn.setImage(UIImage.init(named:"current_keyboard_hidden"), for: .normal)
case 12://删除
btn.tag = baseTag + i
btn.setImage(UIImage.init(named:"current_keyboard_delete"), for: .normal)
let longPressGR = UILongPressGestureRecognizer(target: self, action:#selector(deleteItemLongPress))
btn.addGestureRecognizer(longPressGR)
case 13://确定
btn.tag = baseTag + i
btn.setTitle("确定", for: .normal)
btn.titleLabel?.font =FONT18
btn.setTitleColor(WHITECOLOR, for: .normal)
btn.backgroundColor = UIColor.hexToUIColor(sourceString: "0084ff")
default:
btn.tag = baseTag + i
btn.setTitle(String(i), for: .normal)
btn.titleLabel?.font =FONT24
btn.setTitleColor(TITLTEXTECOLOR, for: .normal)
}
btn.addTarget(self, action:#selector(btnClickAction), for: .touchUpInside)
self.addSubview(btn)
}
}
override func layoutSubviews() {
super.layoutSubviews()
let width:CGFloat = (self.frame.width -1.5) / 4.0
let height:CGFloat = (self.frame.height -1.5) / 4.0
let lineWidth:CGFloat =0.5
//数字1
self.viewWithTag(baseTag +1)?.frame =makeRect(x: 0, y: lineWidth, width: width, height: height)
//数字2
self.viewWithTag(baseTag +2)?.frame =makeRect(x: width + lineWidth, y: lineWidth, width: width, height: height)
self.viewWithTag(baseTag +3)?.frame =makeRect(x: 2 * width +2 * lineWidth, y: lineWidth, width: width, height: height)
self.viewWithTag(baseTag +4)?.frame =makeRect(x: 0, y: height + lineWidth*2, width: width, height: height)
self.viewWithTag(baseTag +5)?.frame =makeRect(x: width + lineWidth, y: height + 2*lineWidth, width: width, height: height)
self.viewWithTag(baseTag +6)?.frame =makeRect(x: 2 * width +2 * lineWidth, y: height + 2*lineWidth, width: width, height: height)
self.viewWithTag(baseTag +7)?.frame =makeRect(x: 0, y: (height + lineWidth)*2+lineWidth, width: width, height: height)
self.viewWithTag(baseTag +8)?.frame =makeRect(x: width + lineWidth, y: (height + lineWidth)*2+lineWidth, width: width, height: height)
self.viewWithTag(baseTag +9)?.frame =makeRect(x: (width + lineWidth)*2, y: (height + lineWidth)*2+lineWidth, width: width, height: height)
//小数点
self.viewWithTag(baseTag +10)?.frame =makeRect(x: 0, y: (height + lineWidth)*3+lineWidth, width: width, height: height)
//零
self.viewWithTag(baseTag +0)?.frame =makeRect(x: width + lineWidth, y: (height + lineWidth)*3+lineWidth, width: width, height: height)
//键盘
self.viewWithTag(baseTag +11)?.frame =makeRect(x: (width + lineWidth)*2, y: (height + lineWidth)*3+lineWidth, width: width, height: height)
//删除
self.viewWithTag(baseTag +12)?.frame =makeRect(x: (width + lineWidth)*3, y: lineWidth, width: width, height:2*height+2*lineWidth)
//确定
self.viewWithTag(baseTag +13)?.frame =makeRect(x: 3*width + lineWidth*2, y:2*height + 2*lineWidth, width: width, height:2*height+2*lineWidth)
}
@objc func btnClickAction(sender:UIButton) {
let btnTag = sender.tag
switch (btnTag) {
case baseTag +10:
self.clickedDot();
case baseTag +11:
self.clickedKeyBoard()
case baseTag +12:
self.clickedDelete()
case baseTag +13:
self.clickedSure()
default://数字
self.clickedNumber(num: btnTag -baseTag)
}
}
//输入
func insert(text: String) {
let delegate = self.firstResponder?.delegate
let range = selectedRange(inputView: self.firstResponder)
//回调代理方法
delegate?.textField!(self.firstResponder!, shouldChangeCharactersIn: range, replacementString: text)
self.firstResponder?.insertText(text)
}
func selectedRange(inputView: UITextField?) -> NSRange {
let beginning: UITextPosition? = inputView?.beginningOfDocument
let selectedRange: UITextRange? = inputView?.selectedTextRange
let selectionStart: UITextPosition? = selectedRange?.start
let selectionEnd: UITextPosition? = selectedRange?.end
let location: Int = inputView!.offset(from: beginning ??UITextPosition(), to: selectionStart ?? UITextPosition())
let length: Int = inputView!.offset(from: selectionStart ??UITextPosition(), to: selectionEnd ?? UITextPosition())
return NSRange(location: location, length: length)
}
//点击小数点
func clickedDot() {
let text = self.firstResponder?.text
//首位不能输入. 只能输入一个.
if text?.count !=0 && !(text?.contains("."))! {
self.insert(text:".")
}
}
//点击删除
@objc func clickedDelete() {
if (self.firstResponder?.hasText)! {
//光标Range
let selectRange = self.firstResponder?.selectedTextRange
//获取光标的位置
let beginning = self.firstResponder?.beginningOfDocument
let location = self.firstResponder?.offset(from: beginning!, to: (selectRange?.start)!)
let str = NSString.init(string: (self.firstResponder?.text)!)
if str.length <=1{
self.firstResponder?.deleteBackward()
self.insert(text:"")
return
}
if str.substring(with:NSRange.init(location:0, length: 1)) =="0" && str.substring(with:NSRange.init(location:1, length: 1)) =="." && str.length !=2 && location == 2{
//光标移动删除小数点,若小数点前只有整数0,则不能删除
return
}else{
self.firstResponder?.deleteBackward()
self.insert(text:"")
}
}
}
//点击键盘
func clickedKeyBoard() {
self.firstResponder?.resignFirstResponder()
}
//点击确定
func clickedSure() {
self.firstResponder?.resignFirstResponder()
if self.done !=nil {
self.done!()
}
}
//点击数字
func clickedNumber(num:Int) {
let text = self.firstResponder?.text
//首位输入0后,不可继续输入整数,可输入小数点及小数点后两位
if text?.count ==1 && text == "0" {
return
}
if (text?.contains("."))! {
//小数点后最多2位
let index = text?.index(of:".")
let subStr = text?.substring(from: index!)
let cout = subStr?.count
if cout! <= 2 {
self.insert(text:String(num))
}
}
else {//无小数点
//整数最多可以输入9位
let cout = text?.count
if cout! < 9{
self.insert(text:String(num))
}
}
}
//长按删除
@objc func deleteItemLongPress(longPress:UILongPressGestureRecognizer) {
if longPress.state == .began {
deleteTimer = Timer.scheduledTimer(timeInterval: 0.2, target: self, selector: #selector(repeatLongPressDelete), userInfo:nil, repeats: true)
}else if (longPress.state == .ended || longPress.state == .failed || longPress.state == .cancelled){
self.cleanTimer()
}
}
@objc func repeatLongPressDelete() {
if (self.firstResponder?.hasText)! {
self.firstResponder?.deleteBackward()
self.insert(text:"")
}
}
func cleanTimer() {
deleteTimer?.invalidate()
deleteTimer =nil
}
}
在需要使用的地方,这样调用,将数字键盘作为UITextField的inputView即可:
//自定义数字键盘
let keyBoardView = NumberKeyboard()
keyBoardView.firstResponder = moneyTextField
moneyTextField.inputView = keyBoardView
moneyTextField.reloadInputViews()