思路:
1.画9个按钮,通过按钮的选中状态控制按钮.
2.连线通过贝塞尔曲线绘制.
3.校验密码通过给按钮绑定tag值判断.
主要代码:
OC版本:
1 // 2 // NineLockView.m 3 // lockView 4 // 5 // Created by Shaoting Zhou on 2018/1/24. 6 // Copyright © 2018年 Shaoting Zhou. All rights reserved. 7 // 8 9 #import "NineLockView.h" 10 11 CGFloat const btnCount = 9; //九宫格个数 12 CGFloat const btnW = 74; //单个按钮宽 13 CGFloat const btnH = 74; //单个按钮高 14 CGFloat const viewY = 300; //视图Y 15 int const columnCount = 3; //列数 16 #define kScreenWidth [UIScreen mainScreen].bounds.size.width 17 18 @interface NineLockView () 19 @property (nonatomic, strong) NSMutableArray * selectBtnsAry; //选中按钮的数组 20 @property (nonatomic, assign) CGPoint currentPoint; //当前的点 坐标 用于判断最后一个点 21 @end 22 23 24 @implementation NineLockView 25 26 -(NSMutableArray *)selectBtnsAry{ 27 if(!_selectBtnsAry){ 28 _selectBtnsAry = [NSMutableArray array]; 29 } 30 return _selectBtnsAry; 31 } 32 33 //通过代码布局时会调用这个方法 34 -(instancetype)initWithFrame:(CGRect)frame{ 35 if(self = [super initWithFrame:frame]){ 36 self.backgroundColor = [UIColor clearColor]; 37 [self addButton]; 38 } 39 return self; 40 } 41 42 //通过sb xib布局时会调用这个方法 43 -(instancetype)initWithCoder:(NSCoder *)aDecoder{ 44 if(self = [super initWithCoder:aDecoder]){ 45 [self addButton]; 46 } 47 return self; 48 } 49 50 #pragma Mark - 布局按钮 51 - (void)addButton{ 52 CGFloat height = 0;; 53 for (int i = 0; i < btnCount; i++) { 54 UIButton * btn = [UIButton buttonWithType:(UIButtonTypeCustom)]; 55 btn.tag = i; 56 btn.userInteractionEnabled = NO; //不可交互 57 //设置默认的图片 58 [btn setBackgroundImage:[UIImage imageNamed:@"gesture_normal"] forState:(UIControlStateNormal)]; 59 //设置选中的图片 60 [btn setBackgroundImage:[UIImage imageNamed:@"gesture_selected"] forState:(UIControlStateSelected)]; 61 int row = i / columnCount; //第几行 62 int column = i % columnCount; //第几列 63 CGFloat margin = (self.frame.size.width - columnCount * btnW) / (columnCount + 1); //边距 64 CGFloat btnX = margin + column * (btnW + margin); //x轴 65 CGFloat btnY = row * (btnW + margin); //y轴 66 // btn.backgroundColor =[UIColor redColor]; 67 btn.frame = CGRectMake(btnX, btnY, btnW, btnH); 68 height = btnH + btnY; //视图高等于 最后一个点的高+y 69 [self addSubview:btn]; 70 } 71 self.frame = CGRectMake(0, viewY, kScreenWidth, height); //视图frame 72 } 73 74 75 - (CGPoint)pointWithTouch:(NSSet *)touches{ 76 UITouch * touch = [touches anyObject]; 77 CGPoint point = [touch locationInView:self]; 78 return point; 79 } 80 - (UIButton *)buttonWithPoint:(CGPoint)point{ 81 for (UIButton * btn in self.subviews) { 82 if(CGRectContainsPoint(btn.frame, point)){ 83 return btn; 84 } 85 } 86 return nil; 87 } 88 89 90 #pragma Mark - 开始移动 91 - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{ 92 //1.拿到触摸的点 93 CGPoint point = [self pointWithTouch:touches]; 94 //2.根据触摸的点拿到相应的按钮 95 UIButton * btn = [self buttonWithPoint:point]; 96 //3.设置状态 97 if(btn && btn.selected == NO){ 98 btn.selected = YES; 99 [self.selectBtnsAry addObject:btn]; 100 } 101 102 103 } 104 105 #pragma Mark - 移动中 106 - (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{ 107 //1.拿到触摸的点 108 CGPoint point = [self pointWithTouch:touches]; 109 //2.根据触摸的点拿到相应的按钮 110 UIButton * btn = [self buttonWithPoint:point]; 111 //3.设置状态 112 if(btn && btn.selected == NO){ 113 btn.selected = YES; 114 [self.selectBtnsAry addObject:btn]; 115 }else{ 116 self.currentPoint = point; 117 } 118 [self setNeedsDisplay]; 119 } 120 121 #pragma Mark - 结束移动 122 - (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{ 123 if([self.delegete respondsToSelector:@selector(lockView:didFinishPath:)]){ 124 NSMutableString * path = [NSMutableString string]; 125 for (UIButton * btn in self.selectBtnsAry) { 126 [path appendFormat:@"%ld",(long)btn.tag]; 127 } 128 [self.delegete lockView:self didFinishPath:path]; 129 } 130 //清空状态 131 for(int i = 0; i < self.selectBtnsAry.count; i++ ){ 132 UIButton * button = self.selectBtnsAry[i]; 133 button.selected = NO; 134 } 135 [self.selectBtnsAry removeAllObjects]; 136 [self setNeedsDisplay]; 137 } 138 139 #pragma Mark - 取消移动 140 - (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{ 141 [self touchesEnded:touches withEvent:event]; 142 } 143 144 #pragma Mark - 绘图 145 - (void)drawRect:(CGRect)rect{ 146 if(self.selectBtnsAry.count == 0){ 147 return; 148 } 149 UIBezierPath * path = [UIBezierPath bezierPath]; 150 path.lineWidth = 8; 151 path.lineJoinStyle = kCGLineJoinRound; 152 [[UIColor colorWithRed:32/255.0 green:210/255.0 blue:254/255.0 alpha:0.5] set]; 153 //遍历按钮 154 for(int i = 0; i < self.selectBtnsAry.count; i++ ){ 155 UIButton * button = self.selectBtnsAry[i]; 156 NSLog(@"%d",i); 157 if(i == 0){ 158 //设置起点 159 [path moveToPoint:button.center]; 160 }else{ 161 //连线 162 [path addLineToPoint:button.center]; 163 } 164 165 } 166 [path addLineToPoint:self.currentPoint]; //最后一点 连接自己 167 [path stroke]; 168 169 } 170 171 172 173 174 @end
1 // 2 // ViewController.m 3 // lockView 4 // 5 // Created by Shaoting Zhou on 2018/1/24. 6 // Copyright © 2018年 Shaoting Zhou. All rights reserved. 7 // 8 9 #import "ViewController.h" 10 #import "NineLockView.h" 11 12 #define kScreenWidth [UIScreen mainScreen].bounds.size.width 13 #define kScreenHeight [UIScreen mainScreen].bounds.size.height 14 15 @interface ViewController () <NineLockViewDelegate> 16 17 @end 18 19 @implementation ViewController 20 21 - (void)viewDidLoad { 22 [super viewDidLoad]; 23 self.view.backgroundColor = [UIColor brownColor]; 24 NineLockView * lockView = [[NineLockView alloc]initWithFrame:CGRectMake(0, 0, kScreenWidth, kScreenHeight)]; 25 lockView.delegete = self; 26 [self.view addSubview:lockView]; 27 } 28 29 -(void)lockView:(NineLockView *)lockView didFinishPath:(NSString *)path{ 30 if(path.length <= 3){ 31 NSLog(@"请至少连4个点"); 32 return; 33 } 34 if([path isEqualToString:@"01258"]){ 35 NSLog(@"OK"); 36 }else{ 37 NSLog(@"error"); 38 } 39 } 40 41 - (void)didReceiveMemoryWarning { 42 [super didReceiveMemoryWarning]; 43 // Dispose of any resources that can be recreated. 44 } 45 46 47 @end
swift版本:
1 // 2 // ViewController.swift 3 // lockView-Swift 4 // 5 // Created by Shaoting Zhou on 2018/1/25. 6 // Copyright © 2018年 Shaoting Zhou. All rights reserved. 7 // 8 9 import UIKit 10 11 class ViewController: UIViewController,nineLockViewDelegate { 12 13 14 let kScreenHeight = UIScreen.main.bounds.size.height 15 let kScreenWidth = UIScreen.main.bounds.size.width 16 override func viewDidLoad() { 17 super.viewDidLoad() 18 self.view.backgroundColor = UIColor.brown 19 let nineLockView = NineLockView.init(frame: CGRect.init(x: 0, y: 0, width: kScreenWidth, height: kScreenHeight)) 20 nineLockView.delegate = self 21 self.view.addSubview(nineLockView) 22 23 // Do any additional setup after loading the view, typically from a nib. 24 } 25 //MARK: - 代理方法 26 func lockView(lockView: NineLockView, path: String) { 27 if(path.description.count < 4){ 28 print("至少连4个"); 29 return; 30 } 31 if(path == "01258"){ 32 print("密码正确"); 33 }else{ 34 print("密码错误"); 35 } 36 } 37 38 39 override func didReceiveMemoryWarning() { 40 super.didReceiveMemoryWarning() 41 // Dispose of any resources that can be recreated. 42 } 43 44 45 }
1 // 2 // NineLockView.swift 3 // lockView-Swift 4 // 5 // Created by Shaoting Zhou on 2018/1/25. 6 // Copyright © 2018年 Shaoting Zhou. All rights reserved. 7 // 8 9 import UIKit 10 11 let btnCount = 9; //九宫格个数 12 let btnW:CGFloat = 74.0; //单个按钮宽 13 let btnH:CGFloat = 74.0; //单个按钮高 14 let viewY:CGFloat = 300.0; //视图Y 15 let columnCount = 3; //列数 16 let kScreenHeight = UIScreen.main.bounds.size.height 17 let kScreenWidth = UIScreen.main.bounds.size.width 18 19 //创建协议 20 protocol nineLockViewDelegate:NSObjectProtocol 21 { 22 func lockView(lockView:NineLockView,path:String) 23 } 24 25 class NineLockView: UIView { 26 weak var delegate:nineLockViewDelegate? 27 var selectBtnsAry = [UIButton] () 28 var currentPoint:CGPoint! 29 30 override init(frame: CGRect) { 31 super.init(frame: frame) 32 self.backgroundColor = UIColor.clear 33 self .addButton(); 34 } 35 36 // MARK: 添加按钮 37 func addButton(){ 38 var height:CGFloat = 0.0 39 for var i in 0 ..< btnCount{ 40 let btn = UIButton.init(type: .custom) 41 btn.setImage(#imageLiteral(resourceName: "gesture_normal"), for: .normal) //默认图片 42 btn.setImage(#imageLiteral(resourceName: "gesture_selected"), for: .selected) //选中图片 43 btn.tag = i 44 btn.isUserInteractionEnabled = false //取消用户交互 45 let row = i / columnCount //行数 46 let column = i % columnCount //列数 47 let margin:CGFloat = (self.frame.size.width - CGFloat(columnCount) * btnW) / CGFloat( (columnCount + 1)); //边距 48 let btnX:CGFloat = margin + CGFloat(column) * (btnW + margin); //x轴 49 let btnY:CGFloat = CGFloat(row) * (btnW + margin); //y轴 50 btn.frame = CGRect.init(x: btnX, y: btnY, width: btnW, height: btnH) 51 height = btnY + btnH //视图的高 = 最后一个按钮的高 + y 52 self.addSubview(btn) 53 } 54 self.frame = CGRect.init(x: 0, y: viewY, width: kScreenWidth, height: height) 55 } 56 57 func pointWithTouch(touches:Set<UITouch>) -> CGPoint{ 58 let touch:UITouch = (touches as NSSet).anyObject() as! UITouch 59 let point = touch.location(in: self) 60 return point; 61 } 62 func buttonWithPoint(point:CGPoint) -> UIButton?{ 63 for var view:UIView in self.subviews { 64 let btn:UIButton = view as! UIButton 65 if(btn.frame.contains(point)){ 66 return btn 67 } 68 } 69 return nil 70 } 71 72 73 // MARK: 开始移动 74 override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { 75 //1.拿到触摸的点 76 let point:CGPoint = self.pointWithTouch(touches: touches) 77 //2.根据触摸的点拿到相应的按钮 78 guard let btn:UIButton = self.buttonWithPoint(point: point) else{ 79 return; 80 } 81 //3.设置状态 82 if(btn.isSelected == false){ 83 btn.isSelected = true 84 self.selectBtnsAry.append(btn) 85 } 86 87 } 88 89 // MARK: 移动中 90 override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) { 91 //1.拿到触摸的点 92 let point:CGPoint = self.pointWithTouch(touches: touches) 93 //2.根据触摸的点拿到相应的按钮 94 guard let btn:UIButton = self.buttonWithPoint(point: point) else{ 95 return; 96 } 97 //3.设置状态 98 if(btn.isSelected == false){ 99 btn.isSelected = true 100 self.selectBtnsAry.append(btn) 101 }else{ 102 self.currentPoint = point; 103 } 104 self.setNeedsDisplay() 105 106 } 107 // MARK: 移动停止 108 override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) { 109 if delegate != nil{ 110 var str = ""; 111 for var i in 0 ..< self.selectBtnsAry.count{ 112 let btn:UIButton = self.selectBtnsAry[i] 113 str = str + String(btn.tag) 114 } 115 self.delegate?.lockView(lockView: self, path: str) 116 } 117 118 for var i in 0 ..< self.selectBtnsAry.count{ 119 let btn:UIButton = self.selectBtnsAry[i] 120 btn.isSelected = false 121 } 122 self.selectBtnsAry.removeAll() 123 self.setNeedsDisplay() 124 } 125 126 // MARK: 移动取消 127 override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) { 128 self.touchesEnded(touches, with: event) 129 } 130 131 // MARK: 绘图 132 override func draw(_ rect: CGRect) { 133 if(self.selectBtnsAry.count == 0){ 134 return; 135 } 136 let path:UIBezierPath = UIBezierPath.init() 137 path.lineWidth = 8 138 path.lineJoinStyle = .round 139 UIColor.init(red: 32/255.0, green: 210/255.0, blue: 254/255.0, alpha: 0.5).set() 140 //遍历按钮 141 for var i in 0 ..< self.selectBtnsAry.count{ 142 let btn:UIButton = self.selectBtnsAry[i] 143 if(i == 0){ 144 //起点 145 path.move(to: btn.center) 146 }else{ 147 //划线 148 path.addLine(to: btn.center) 149 } 150 } 151 path.addLine(to: self.currentPoint) //最后一点 连接自己 152 path.stroke() 153 } 154 155 156 required init?(coder aDecoder: NSCoder) { 157 fatalError("init(coder:) has not been implemented") 158 } 159 160 }
基本演示:
这里的只演示下基本九宫格校验密码(密码已经存在:01258).
创建密码,修改密码思路类似.
github: https://github.com/pheromone/iOS-nineLock