//1.定义继承自UIView的CaptchaView,直接上代码
import UIKit
// MARK: 基本的样式
struct CaptchaViewStytel {
/// 随机颜色
var kRandomColor:UIColor{
return UIColor.init(red: CGFloat(Float(arc4random()%255)/255.0), green: CGFloat(Float(arc4random()%255)/255.0), blue: CGFloat(Float(arc4random()%255)/255.0), alpha: 1.0)
}
/// 线数量
var kLineCount = 6
/// 线宽
var kLineWidth = 1.0
/// 字符数量
var kCharCount = 4
/// 随机字体大小
var kFontSize:UIFont?{
return UIFont.systemFont(ofSize: CGFloat(Float(arc4random()%5) + 18))
}
}
class CaptchaView: UIView {
/// 字符素材数组
var changeArray: NSArray?
/// 验证码的字符串
var changeString: String?
/// 基本样式
var stytel:CaptchaViewStytel!
override init(frame: CGRect) {
super.init(frame: frame)
// 初始化
self.setUpUI()
// 显示一个随机验证码
self.changeCaptcha()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// MARK: 初始化
func setUpUI() -> Void {
let stytel = CaptchaViewStytel()
self.stytel = stytel
self.backgroundColor = stytel.kRandomColor
//设置layer圆角半径
//self.layer.cornerRadius = 5.0
//隐藏边界
//self.layer.masksToBounds = true
}
// MARK: 布局约束
override func layoutSubviews() {
super.layoutSubviews()
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.backgroundColor = stytel.kRandomColor
//点击界面,切换验证码
self.changeCaptcha()
//setNeedsDisplay调用drawRect方法来实现view的绘制
self.setNeedsDisplay()
}
// MARK: 显示一个随机验证码
func changeCaptcha(){
// 从字符数组中随机抽取相应数量的字符,组成验证码字符串
// 数组中存放的是全部可选的字符,可以是字母,也可以是中文
let changeArray = ["0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"]
self.changeArray = changeArray as NSArray
self.changeString = String()
// 随机从数组中选取需要个数的字符,然后拼接为一个字符串
for _ in 0..<stytel.kCharCount {
let index = arc4random()%(UInt32(changeArray.count - 1))
let getStr = changeArray[Int(index)]
self.changeString = "\(self.changeString!)\(getStr)"
}
// 从网络获取字符串,然后把得到的字符串在本地绘制出来(网络获取步骤在这省略)
print("\(self.changeString!)")
}
// MARK:绘制界面(1.UIView初始化后自动调用; 2.调用setNeedsDisplay方法时会自动调用)
override func draw(_ rect: CGRect) {
// 重写父类方法,首先要调用父类的方法
super.draw(rect)
//设置随机背景颜色
self.backgroundColor = stytel.kRandomColor
//获得要显示验证码字符串,根据长度,计算每个字符显示的大概位置
let text = self.changeString
let cSize = NSString(string: "S").size(withAttributes: [NSAttributedString.Key.font : UIFont.systemFont(ofSize: 20)])
// 每个字符显示宽度的位置
let width = (rect.size.width / CGFloat(text!.count)) - CGFloat(cSize.width)
// 每个字符所显示高度位置
let height = rect.size.height - cSize.height
var point: CGPoint
//依次绘制每一个字符,可以设置显示的每个字符的字体大小、颜色、样式等
var pX,PY: CGFloat
for i in 0..<text!.count {
pX = CGFloat(Float(arc4random()%UInt32(width))) + rect.size.width / CGFloat(text!.count)*CGFloat(i)
PY = CGFloat(Float(arc4random()%UInt32(height)))
point = CGPoint(x: pX, y: PY)
let texta = text! as NSString
let c = texta.character(at: i)
let textC = NSString(format: "%C", c)
textC.draw(at: point, withAttributes: [NSAttributedString.Key.font : stytel.kFontSize!])
}
//调用drawRect:之前,系统会向栈中压入一个CGContextRef,调用UIGraphicsGetCurrentContext()会取栈顶的CGContextRef
let context = UIGraphicsGetCurrentContext()
// 设置画线宽度
context?.setLineWidth(CGFloat(stytel!.kLineWidth))
// 绘制干扰的彩色直线
for _ in 0..<stytel.kLineCount {
// 设置线的随机颜色
context?.setStrokeColor(stytel!.kRandomColor.cgColor)
// 设置线的起点
pX = CGFloat(Float(arc4random()%UInt32(rect.size.width)))
PY = CGFloat(Float(arc4random()%UInt32(rect.size.height)))
context?.move(to: CGPoint(x: pX, y: PY))
//设置线终点
pX = CGFloat(Float(arc4random()%UInt32(rect.size.width)))
PY = CGFloat(Float(arc4random()%UInt32(rect.size.height)))
context?.addLine(to: CGPoint(x: pX, y: PY))
// 画线
context?.strokePath()
}
}
}
2.使用
import UIKit
class LSLoginViewController: LSBaseController, UITextFieldDelegate {
var captchaView : CaptchaView!//本地验证码
var tex_CompanyCode: UITextField!//验证码
override func viewDidLoad() {
super.viewDidLoad()
addSubViews()
}
func addSubViews(){
//显示验证码界面
captchaView = CaptchaView.init()
headeBGView.addSubview(captchaView)
captchaView.snp.makeConstraints { (make) in
make.right.equalTo(headeBGView).offset(-RESIZE(x: 20))
make.top.equalTo(tex_CompanyCode)
make.width.equalTo(RESIZE(x: 100))
make.height.equalTo(RESIZE(x: 30))
}
tex_CompanyCode = createTextField(content: "验证码")
headeBGView.addSubview(tex_CompanyCode)
tex_CompanyCode.clearButtonMode = UITextField.ViewMode.never //编辑时出现清除按钮
tex_CompanyCode.snp.makeConstraints { (make) in
make.left.height.equalTo(tex_UserName)
make.right.equalTo(headeBGView.snp.right).offset(-RESIZE(x: 120))
make.centerY.equalTo(imageCompanyCode.snp.centerY)
}
}
@objc func btn_ClickLogin(sender: UIButton){
if tex_CompanyCode.text?.lowercased() != captchaView.changeString?.lowercased() {
//本地验证码不正确
let anim = CAKeyframeAnimation.init(keyPath: "transform.translation.x")
anim.repeatCount = 1
anim.values = [-20,20,-20]
captchaView.layer.add(anim, forKey: nil)
tex_CompanyCode.layer.add(anim, forKey: nil)
self.showToast("验证码错误,请重新输入")
return
}
LSPrint(message: "登录请求")
}
}
网友评论