思路:

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 = ; //九宫格个数
  12. CGFloat const btnW = ; //单个按钮宽
  13. CGFloat const btnH = ; //单个按钮高
  14. CGFloat const viewY = ; //视图Y
  15. int const columnCount = ; //列数
  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. @implementation NineLockView
  24.  
  25. -(NSMutableArray *)selectBtnsAry{
  26. if(!_selectBtnsAry){
  27. _selectBtnsAry = [NSMutableArray array];
  28. }
  29. return _selectBtnsAry;
  30. }
  31.  
  32. //通过代码布局时会调用这个方法
  33. -(instancetype)initWithFrame:(CGRect)frame{
  34. if(self = [super initWithFrame:frame]){
  35. self.backgroundColor = [UIColor clearColor];
  36. [self addButton];
  37. }
  38. return self;
  39. }
  40.  
  41. //通过sb xib布局时会调用这个方法
  42. -(instancetype)initWithCoder:(NSCoder *)aDecoder{
  43. if(self = [super initWithCoder:aDecoder]){
  44. [self addButton];
  45. }
  46. return self;
  47. }
  48.  
  49. #pragma Mark - 布局按钮
  50. - (void)addButton{
  51. CGFloat height = ;;
  52. for (int i = ; i < btnCount; i++) {
  53. UIButton * btn = [UIButton buttonWithType:(UIButtonTypeCustom)];
  54. btn.tag = i;
  55. btn.userInteractionEnabled = NO; //不可交互
  56. //设置默认的图片
  57. [btn setBackgroundImage:[UIImage imageNamed:@"gesture_normal"] forState:(UIControlStateNormal)];
  58. //设置选中的图片
  59. [btn setBackgroundImage:[UIImage imageNamed:@"gesture_selected"] forState:(UIControlStateSelected)];
  60. int row = i / columnCount; //第几行
  61. int column = i % columnCount; //第几列
  62. CGFloat margin = (self.frame.size.width - columnCount * btnW) / (columnCount + ); //边距
  63. CGFloat btnX = margin + column * (btnW + margin); //x轴
  64. CGFloat btnY = row * (btnW + margin); //y轴
  65. // btn.backgroundColor =[UIColor redColor];
  66. btn.frame = CGRectMake(btnX, btnY, btnW, btnH);
  67. height = btnH + btnY; //视图高等于 最后一个点的高+y
  68. [self addSubview:btn];
  69. }
  70. self.frame = CGRectMake(, viewY, kScreenWidth, height); //视图frame
  71. }
  72.  
  73. - (CGPoint)pointWithTouch:(NSSet *)touches{
  74. UITouch * touch = [touches anyObject];
  75. CGPoint point = [touch locationInView:self];
  76. return point;
  77. }
  78. - (UIButton *)buttonWithPoint:(CGPoint)point{
  79. for (UIButton * btn in self.subviews) {
  80. if(CGRectContainsPoint(btn.frame, point)){
  81. return btn;
  82. }
  83. }
  84. return nil;
  85. }
  86.  
  87. #pragma Mark - 开始移动
  88. - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
  89. //1.拿到触摸的点
  90. CGPoint point = [self pointWithTouch:touches];
  91. //2.根据触摸的点拿到相应的按钮
  92. UIButton * btn = [self buttonWithPoint:point];
  93. //3.设置状态
  94. if(btn && btn.selected == NO){
  95. btn.selected = YES;
  96. [self.selectBtnsAry addObject:btn];
  97. }
  98.  
  99. }
  100.  
  101. #pragma Mark - 移动中
  102. - (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
  103. //1.拿到触摸的点
  104. CGPoint point = [self pointWithTouch:touches];
  105. //2.根据触摸的点拿到相应的按钮
  106. UIButton * btn = [self buttonWithPoint:point];
  107. //3.设置状态
  108. if(btn && btn.selected == NO){
  109. btn.selected = YES;
  110. [self.selectBtnsAry addObject:btn];
  111. }else{
  112. self.currentPoint = point;
  113. }
  114. [self setNeedsDisplay];
  115. }
  116.  
  117. #pragma Mark - 结束移动
  118. - (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
  119. if([self.delegete respondsToSelector:@selector(lockView:didFinishPath:)]){
  120. NSMutableString * path = [NSMutableString string];
  121. for (UIButton * btn in self.selectBtnsAry) {
  122. [path appendFormat:@"%ld",(long)btn.tag];
  123. }
  124. [self.delegete lockView:self didFinishPath:path];
  125. }
  126. //清空状态
  127. for(int i = ; i < self.selectBtnsAry.count; i++ ){
  128. UIButton * button = self.selectBtnsAry[i];
  129. button.selected = NO;
  130. }
  131. [self.selectBtnsAry removeAllObjects];
  132. [self setNeedsDisplay];
  133. }
  134.  
  135. #pragma Mark - 取消移动
  136. - (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
  137. [self touchesEnded:touches withEvent:event];
  138. }
  139.  
  140. #pragma Mark - 绘图
  141. - (void)drawRect:(CGRect)rect{
  142. if(self.selectBtnsAry.count == ){
  143. return;
  144. }
  145. UIBezierPath * path = [UIBezierPath bezierPath];
  146. path.lineWidth = ;
  147. path.lineJoinStyle = kCGLineJoinRound;
  148. [[UIColor colorWithRed:/255.0 green:/255.0 blue:/255.0 alpha:0.5] set];
  149. //遍历按钮
  150. for(int i = ; i < self.selectBtnsAry.count; i++ ){
  151. UIButton * button = self.selectBtnsAry[i];
  152. NSLog(@"%d",i);
  153. if(i == ){
  154. //设置起点
  155. [path moveToPoint:button.center];
  156. }else{
  157. //连线
  158. [path addLineToPoint:button.center];
  159. }
  160.  
  161. }
  162. [path addLineToPoint:self.currentPoint]; //最后一点 连接自己
  163. [path stroke];
  164.  
  165. }
  166.  
  167. @end

OC版本

  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(, , 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 <= ){
  31. NSLog(@"请至少连4个点");
  32. return;
  33. }
  34. if([path isEqualToString:@""]){
  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. @end

OC版本

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. let kScreenHeight = UIScreen.main.bounds.size.height
  14. let kScreenWidth = UIScreen.main.bounds.size.width
  15. override func viewDidLoad() {
  16. super.viewDidLoad()
  17. self.view.backgroundColor = UIColor.brown
  18. let nineLockView = NineLockView.init(frame: CGRect.init(x: 0, y: 0, width: kScreenWidth, height: kScreenHeight))
  19. nineLockView.delegate = self
  20. self.view.addSubview(nineLockView)
  21.  
  22. // Do any additional setup after loading the view, typically from a nib.
  23. }
  24. //MARK: - 代理方法
  25. func lockView(lockView: NineLockView, path: String) {
  26. if(path.description.count < 4){
  27. print("至少连4个");
  28. return;
  29. }
  30. if(path == "01258"){
  31. print("密码正确");
  32. }else{
  33. print("密码错误");
  34. }
  35. }
  36.  
  37. override func didReceiveMemoryWarning() {
  38. super.didReceiveMemoryWarning()
  39. // Dispose of any resources that can be recreated.
  40. }
  41.  
  42. }

Swift版本

  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. // MARK: 开始移动
  73. override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
  74. //1.拿到触摸的点
  75. let point:CGPoint = self.pointWithTouch(touches: touches)
  76. //2.根据触摸的点拿到相应的按钮
  77. guard let btn:UIButton = self.buttonWithPoint(point: point) else{
  78. return;
  79. }
  80. //3.设置状态
  81. if(btn.isSelected == false){
  82. btn.isSelected = true
  83. self.selectBtnsAry.append(btn)
  84. }
  85.  
  86. }
  87.  
  88. // MARK: 移动中
  89. override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
  90. //1.拿到触摸的点
  91. let point:CGPoint = self.pointWithTouch(touches: touches)
  92. //2.根据触摸的点拿到相应的按钮
  93. guard let btn:UIButton = self.buttonWithPoint(point: point) else{
  94. return;
  95. }
  96. //3.设置状态
  97. if(btn.isSelected == false){
  98. btn.isSelected = true
  99. self.selectBtnsAry.append(btn)
  100. }else{
  101. self.currentPoint = point;
  102. }
  103. self.setNeedsDisplay()
  104.  
  105. }
  106. // MARK: 移动停止
  107. override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
  108. if delegate != nil{
  109. var str = "";
  110. for var i in 0 ..< self.selectBtnsAry.count{
  111. let btn:UIButton = self.selectBtnsAry[i]
  112. str = str + String(btn.tag)
  113. }
  114. self.delegate?.lockView(lockView: self, path: str)
  115. }
  116.  
  117. for var i in 0 ..< self.selectBtnsAry.count{
  118. let btn:UIButton = self.selectBtnsAry[i]
  119. btn.isSelected = false
  120. }
  121. self.selectBtnsAry.removeAll()
  122. self.setNeedsDisplay()
  123. }
  124.  
  125. // MARK: 移动取消
  126. override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
  127. self.touchesEnded(touches, with: event)
  128. }
  129.  
  130. // MARK: 绘图
  131. override func draw(_ rect: CGRect) {
  132. if(self.selectBtnsAry.count == 0){
  133. return;
  134. }
  135. let path:UIBezierPath = UIBezierPath.init()
  136. path.lineWidth = 8
  137. path.lineJoinStyle = .round
  138. UIColor.init(red: 32/255.0, green: 210/255.0, blue: 254/255.0, alpha: 0.5).set()
  139. //遍历按钮
  140. for var i in 0 ..< self.selectBtnsAry.count{
  141. let btn:UIButton = self.selectBtnsAry[i]
  142. if(i == 0){
  143. //起点
  144. path.move(to: btn.center)
  145. }else{
  146. //划线
  147. path.addLine(to: btn.center)
  148. }
  149. }
  150. path.addLine(to: self.currentPoint) //最后一点 连接自己
  151. path.stroke()
  152. }
  153.  
  154. required init?(coder aDecoder: NSCoder) {
  155. fatalError("init(coder:) has not been implemented")
  156. }
  157.  
  158. }

Swift版本

基本演示:

这里的只演示下基本九宫格校验密码(密码已经存在:01258).

创建密码,修改密码思路类似.

github: https://github.com/pheromone/iOS-nineLock

iOS 九宫格解锁的更多相关文章

  1. appium 九宫格解锁招商银行手机客户端app

    之前研究了一段时间的appium for native app 相应的总结如下:                                            appium测试环境搭建 :ht ...

  2. App自动化(2)--Python&Appium实现安卓手机九宫格解锁

    九宫格作为常见的手势密码,我们在使用的时候,是从起点开始,按住不放,然后滑动手指,直到最后一个点松开手指,如果与设置的手势密码匹配,则解锁成功. 现在大多数九宫格作为一个元素存在,很难定位到每一个点. ...

  3. iOS 指纹解锁 验证TouchID

    iOS指纹解锁 1.首先,引入依赖框架 LocalAuthentication.framework #import <LocalAuthentication/LocalAuthenticatio ...

  4. iOS 九宫格手势密码

    代码地址如下:http://www.demodashi.com/demo/11490.html 一.准备工作 需要准备什么环境 xcode,iOS8+ 本例子实现什么功能 主要实现手势密码设置,验证 ...

  5. Android之九宫格解锁的实现

        <ignore_js_op>                                                  下面是最重要的那个LocusPassWordView ...

  6. uiautomator2 实现App九宫格解锁

    App九宫格解锁 之前在testerhome社区看见codeskyblue大佬写过一种方法,但是这种办法存在一个弊端,那就是多个点的坐标是写死的,也就是说要是换了部手机,九宫格解锁就行不通了,于是就想 ...

  7. Python+Appium自动化测试(10)-TouchAction类与MultiAction类(控件元素的滑动、拖动,九宫格解锁,手势操作等)

    滑动屏幕方法swipe一般用于对页面进行上下左右滑动操作,但自动化过程中还会遇到其他情况,如对控件元素进行滑动.拖拽操作,九宫格解锁,手势操作,地图的放大与缩小等.这些需要针对控件元素的滑动操作,或者 ...

  8. iOS开发 - Swift - 自己写的一个九宫格解锁的Demo

    前段时间做项目,公司要用到一个九宫格的手势解锁的需求. 虽然在很多地方都可以找到写好的第三方源码, 但是我的性格是不喜欢Ctrl+V的,于是自己凭着理解敲了一个出来,功能很简单,只是单纯的返回结果.附 ...

  9. IOS仿Android九宫格解锁效果[转]

    原理很简单,监听view中touch的一系列事件,当判定手指位置在某个按钮附近的时候则判断此按钮选中,并画出线. 效果图如下: 你可以在NineGridUnlockView.m文件中方法 touche ...

随机推荐

  1. PAT 1136 A Delayed Palindrome

    1136 A Delayed Palindrome (20 分)   Consider a positive integer N written in standard notation with k ...

  2. 102. Binary Tree Level Order Traversal二叉树层序遍历

    网址:https://leetcode.com/problems/binary-tree-level-order-traversal/ 参考:https://www.cnblogs.com/grand ...

  3. java Comparable and Comparator

    1.Comparable简介 此接口对实现它的每个类的对象强加一个总排序.这种排序被称为类的自然排序,类的compareTo方法被称为其自然比较方法.可以通过 Collections.sort(和Ar ...

  4. thymeleaf下拉框从后台动态获取集合数据并回显选中

    今天遇到从后台集合中取出对象在前台页面下拉列表展示: <select name="signature" lay-search="" class=" ...

  5. Python3+Scapy安装使用教程

    一.说明 之前写DoS程序的时候(见"拒绝服务(DoS)理解.防御与实现"),数据包完全是自己构造的,这其中的难处一是要清楚各层协议的字段.字段长度.字段是数值还是字符.大头还是小 ...

  6. CentOS下运行Java文件Error: Could not find or load main class

    今天,因为测试拷贝一个JvmTest.java文件到CentOS虚机上运行,发现文件编译没有问题,但运行时却报错,如下图: Java代码如下: package com.zhi.test; public ...

  7. 干货!一篇文章集合所有Linux基础命令

    1 文件{ls -rtl # 按时间倒叙列出所有目录和文件 ll -rttouch file # 创建空白文件rm -rf 目录名 # 不提示删除非空目录(-r:递归删除 -f强制)dos2unix ...

  8. 【调试基础】Part 2 文本字符

    01 字节存储顺序 大端:低字节存在高地址,高字节存在低地址.eg:IBM: 小端:低字节存在低地址,高字节存在高地址.eg:INTEL: 02 字符集 ASCII:128=26小写 + 26大写 + ...

  9. Linux Mysql创建用户并分配权限

    1.查看全部的用户: select user,host from mysql.user\G; 2.新建用户: create user  ‘用户名’@‘主机名’  identified by ‘用户密码 ...

  10. 'weinre' 不是内部或外部命令,也不是可运行的程序 或批处理文件。 解决方案

    使用 npm install -g weinre 全局安装 weinre,weinre 安装目录是:C:\Users\Administrator\AppData\Roaming\npm 需要配置环境变 ...