界面是一个九宫格的布局.九宫格实现思路.
先确定有多少列 cloum = 3;
计算出每列之间的距离
计算为: CGFloat margin = (当前View的宽度 - 列数 * 按钮的宽度) / 总列数 + 1
每一列的X的值与它当前所在的行有关
当前所在的列为:curColum = i % cloum
每一行的Y的值与它当前所在的行有关.
当前所在的行为:curRow = i / cloum
 
每一个按钮的X值为, margin + 当前所在的列 * (按钮的宽度+ 每个按钮之间的间距)
每一个按钮的Y值为 当前所在的行 * (按钮的宽度 + 每个按钮之间的距离)
 
无论是Xib,还是代码,都做一次初始化
 

step1:界面搭建

-(void)awakeFromNib{
初始化
[self setUP];
} -(instancetype)initWithFrame:(CGRect)frame{
if (self = [super initWithFrame:frame]) {
初始化
[self setUP];
}
return self;
} 初始化
- (void)setUP{ for (int i = 0; i < 9; i++) {
添加按钮
UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
设置图片
[btn setImage:[UIImage imageNamed:@"gesture_node_normal"] forState:UIControlStateNormal];
设置选中状态的下图片
[btn setImage:[UIImage imageNamed:@"gesture_node_highlighted"] forState:UIControlStateSelected];
添加按钮
[self addSubview:btn];
}
} 布局子控件
- (void)layoutSubviews{
[super layoutSubviews];
总列数
int cloumn = 3;
CGFloat btnWH = 74;
每列之间的间距
CGFloat margin = (self.bounds.size.width - cloumn * btnWH) / (cloumn + 1);
当前所在的列
int curClounm = 0;
当前所在的行
int curRow = 0;
CGFloat x = 0;
CGFloat y = 0;
取出所有的控件
for (int i = 0; i < self.subviews.count; i++) {
计算当前所在的列
curClounm = i % cloumn;
计算当前所在的行.
curRow = i / cloumn;
计算Y
x = margin + (margin + btnWH) * curClounm;
计算Y.
y = (margin +btnWH) * curRow;
UIButton *btn = self.subviews[i];
btn.frame = CGRectMake(x, y, btnWH, btnWH);
}
}

step2:按钮选中

 /**
* 获取当前手指所在的点
*
* @param touches touches集合
*
* @return 当前手指所在的点.
*/
- (CGPoint)getCurrentPoint:(NSSet *)touches{
UITouch *touch = [touches anyObject];
return [touch locationInView:self];
} /**
* 判断一个点在不在按钮上.
*
* @param point 当前点
*
* @return 如果在按钮上, 返回当前按钮, 如果不在返回nil.
*/
- (UIButton *)btnRectContainsPoint:(CGPoint)point{
遍历所有的子控件
for (UIButton *btn in self.subviews) {
判断手指当前点在不在按钮上.
if (CGRectContainsPoint(btn.frame, point)) {
在按钮上.返回当前按钮
return btn;
}
}
return nil; } 手指点击时让按钮成选中状态
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{ 判断当前手指在不在按钮上,如果在按钮上, 让按钮成为选中状态.
.获取当前手指所在的点
CGPoint curP = [self getCurrentPoint:touches];
.判断当前手指所在的点在不在按钮上.
UIButton *btn = [self btnRectContainsPoint:curP];
if (btn) {
btn.selected = YES;
}
} 手指移动时,按钮选中,连线到当前选中的按钮
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{ 判断当前手指在不在按钮上,如果在按钮上, 让按钮成为选中状态.
.获取当前手指所在的点
CGPoint curP = [self getCurrentPoint:touches];
.判断当前手指所在的点在不在按钮上.
UIButton *btn = [self btnRectContainsPoint:curP];
if (btn) {
btn.selected = YES;
}
}

step3:连线

 @interface ClockView()

 /**
* 选中的按钮数组.
* 每次选中一个按钮时,都把按钮添加到数组当中.移动添加到按钮当中时做一次重绘.
* 重绘过程中取出所有保存的按钮, 判断是不是第一个按钮, 如果是第一个按钮,那就让它成为路径的起点.
* 如果不是第一个按钮,那就添加一根线到按钮的中心点.
*/
@property(nonatomic,strong)NSMutableArray *selectBtn; @end 懒加载数组.
-(NSMutableArray *)selectBtn{
if (_selectBtn == nil) {
_selectBtn = [NSMutableArray array];
}
return _selectBtn;
} 手指点击时让按钮成选中状态
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{ 判断当前手指在不在按钮上,如果在按钮上, 让按钮成为选中状态.
.获取当前手指所在的点
CGPoint curP = [self getCurrentPoint:touches]; .判断当前手指所在的点在不在按钮上.
UIButton *btn = [self btnRectContainsPoint:curP];
if (btn && btn.selected == NO) {如果按钮已经是选中状态,就不让它再添加到数组当中
让按钮成为选中状态
btn.selected = YES;
把选中按钮添加到数组当中
[self.selectBtn addObject:btn];
}
} 手指移动时,按钮选中,连线到当前选中的按钮
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
判断当前手指在不在按钮上,如果在按钮上, 让按钮成为选中状态.
.获取当前手指所在的点
CGPoint curP = [self getCurrentPoint:touches];
.判断当前手指所在的点在不在按钮上.
UIButton *btn = [self btnRectContainsPoint:curP];
if (btn && btn.selected == NO) {//如果按钮已经是选中状态,就不让它再添加到数组当中
让按钮成为选中状态
btn.selected = YES;
把选中按钮添加到数组当中
[self.selectBtn addObject:btn];
每次添加完毕后做一次重绘.
[self setNeedsDisplay];
}
} - (void)drawRect:(CGRect)rect {
创建路径.
UIBezierPath *path = [UIBezierPath bezierPath];
取出所有保存的选中按钮连线.
for(int i = ; i < self.selectBtn.count;i++){
UIButton *btn = self.selectBtn[i];
判断当前按钮是不是第一个,如果是第一个,把它的中心设置为路径的起点.
if(i == ){
设置起点.
[path moveToPoint:btn.center];
}else{
添加一根线到当前按钮的圆心.
[path addLineToPoint:btn.center];
}
} 设置颜色
[[UIColor redColor] set];
设置线宽
[path setLineWidth:];
设置线的连接样式
[path setLineJoinStyle:kCGLineJoinRound];
绘制路径.
[path stroke];
}

step4:业务逻辑

 @interface ClockView()

 /**
* 选中的按钮数组.
*/
@property(nonatomic,strong)NSMutableArray *selectBtn; /**
* 当前手指移动的点
* 记录当前手指的点,数组当中所有的点都绘制完毕后, 再添加一根线到当前手指所在的点.
*/
@property(nonatomic,assign)CGPoint curP; @end 手指松开时,按钮取消选中状态,清空所有的连线.
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{ .取消所有选中的按钮,查看选中按钮的顺序
NSMutableString *str = [NSMutableString string];
for (UIButton *btn in self.selectBtn) {
[str appendFormat:@"%ld",btn.tag];
btn.selected = NO;
}
.清空所有的连线.
[self.selectBtn removeAllObjects];
.重绘
[self setNeedsDisplay];
NSLog(@"选中按钮顺序为:%@",str);
} - (void)drawRect:(CGRect)rect {
如果数组当中没有元素,就不让它进行绘图.直接返回.
if(self.selectBtn.count <= ) return;
创建路径.
UIBezierPath *path = [UIBezierPath bezierPath];
取出所有保存的选中按钮连线.
for(int i = ; i < self.selectBtn.count;i++){
UIButton *btn = self.selectBtn[i];
判断当前按钮是不是第一个,如果是第一个,把它的中心设置为路径的起点.
if(i == ){
设置起点.
[path moveToPoint:btn.center];
}else{
添加一根线到当前按钮的圆心.
[path addLineToPoint:btn.center];
}
}
连完先中的按钮后, 在选中按钮之后,添加一根线到当前手指所在的点.
[path addLineToPoint:self.curP];
设置颜色
[[UIColor redColor] set];
设置线宽
[path setLineWidth:];
设置线的连接样式
[path setLineJoinStyle:kCGLineJoinRound];
绘制路径.
[path stroke];
}

github下载地址:https://github.com/CrazyZhangSanFeng/shoushijiesuo

iOS仿安卓手势解锁的更多相关文章

  1. iOS-高仿支付宝手势解锁(九宫格)

    概述 高仿支付宝手势解锁, 通过手势枚举去实现手势密码相对应操作. 详细 代码下载:http://www.demodashi.com/demo/10706.html 基上篇[TouchID 指纹解锁] ...

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

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

  3. [ios仿系列]仿支付宝手势解码

    呀~.这么快就转到ios阵营了???.android还有那么多坑呢???为此我也仅仅能啃着馒头留下屈辱的眼泪了. . 本次因为开发公司产品的android版,继而ios版也负责一部分.当中一部分就是手 ...

  4. 在iOS上增加手势锁屏、解锁功能

    在iOS上增加手势锁屏.解锁功能 在一些涉及个人隐私的场景下,尤其是当移动设备包含太多私密信息时,为用户的安全考虑是有必要的. 桌面版的QQ在很多年前就考虑到用户离开电脑后隐私泄露的危险,提供了“离开 ...

  5. iOS绘制手势解锁密码

    手势解锁这个功能其实已经用的越来越少了.但是郁闷不知道我公司为什么每次做一个app都要把手势解锁加上.....于是就自己研究了一下手势解锁页面的实现.. 要想实现这个页面,先说说需要掌握哪些: UIP ...

  6. [iOS UI进阶 - 5.0] 手势解锁Demo

    A.需求 1.九宫格手势解锁 2.使用了绘图和手势事件   code source: https://github.com/hellovoidworld/GestureUnlockDemo     B ...

  7. iOS仿支付宝首页效果

    代码地址如下:http://www.demodashi.com/demo/12776.html 首先看一下效果 状态栏红色是因为使用手机录屏的原因. 1.问题分析 1.导航栏A有两组控件,随着tabl ...

  8. 长沙理工大学第十二届ACM大赛-重现赛C 安卓图案解锁 (模拟)

    链接:https://ac.nowcoder.com/acm/contest/1/C来源:牛客网 安卓图案解锁 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 131072K,其他语言 ...

  9. WPF实现手势解锁

    桌面程序的解锁方式一般是账号密码,互联网的可以使用扫码解锁,甚至人脸识别.但扫码需要网络,人脸识别又较复杂.所以就想把安卓常用的手势解锁移植到桌面程序上. 先来张效果图,有兴趣的往下看,没兴趣的打扰了 ...

随机推荐

  1. 使用spring单元调试出错initializationError

    1.引入spring jar包之后,单元测试一直出错,提示initializationError. 2.在网上看说是junit版本的问题,引入其他版本之后,还是不对. 3.最后发现是需要引入 这两个j ...

  2. 【设计模式】—— 解释器模式Interpret

    前言:[模式总览]——————————by xingoo 模式意图 自定义某种语言后,给定一种文法标准,定义解释器,进行解析. 做过搜索的朋友们可能更了解一些,平时我们搜索所需要的词库,通常就需要用这 ...

  3. redis后台启动配置

    在cmd窗口启动redis,窗口关闭后再次操作会报错. 将redis安装为服务,可使其在后台启动,无须担心误操作关闭服务窗口. 配置如下: 进入redis目录,输入如下命令执行即可: redis-se ...

  4. BZOJ 1565 [NOI2009]植物大战僵尸 | 网络流

    传送门 BZOJ 1565 题解 这道题也是个经典的最大权闭合子图-- 复习一下最大权闭合子图是什么? 就是一个DAG上,每个点有个或正或负的点权,有的点依赖于另外一些点(如果选这个点,则被依赖点必选 ...

  5. CentOS安装git及使用Gitolite来管理版本库

    首先吐槽一下网上的各种教程,大部分都扯蛋,估计都是些所谓的"编辑"在网上瞎抄来的-- 以下内容都是基于CentOS的服务器端,Mac OS X的客户端. 如果是使用的Windows ...

  6. 弹指之间 -- Prerequisites

    CHAPTER 1 吉他的分类 Electric Guitar Classic Guitar Folk Guitar CHAPTER 2 吉他各部名称 CHAPTER 3 选购吉他 琴颈弯曲程度 木头 ...

  7. LRN

    转自https://blog.csdn.net/u011204487/article/details/76026537 LRN全称为Local Response Normalization,即局部响应 ...

  8. 【1】ConcurrentModificationException 异常解析和快速失败,安全失败

    目录 一.引起异常的代码 二.foreach原理 三.从ArrayList源码找原因 四.单线程解决方案 五.在多线程环境下的解决方法 一.引起异常的代码 以下三种的遍历集合对象时候,执行集合的rem ...

  9. linux课程总结

    linux课程总结 --20125111 李冰清 转眼间,为期十六周的linux课程已进入尾声,回想起这十六周的课程,不断浮现在脑海里的是娄老师的笑容以及这十六周以来的点点滴滴. 第一次听到娄老师说将 ...

  10. Python 算法实现

    # [程序1] # 题目:有1.2.3.4个数字,能组成多少个互不相同且无重复数字的三位数?都是多少? l=[1,2,3,4] count = 0 for i in range(len(l)): fo ...