终于效果图:


控制器:
//
// BeyondViewController.m
// 39_触摸解锁
//
// Created by beyond on 14-9-17.
// Copyright (c) 2014年 com.beyond. All rights reserved.
// #import "BeyondViewController.h"
#import "LockView.h"
#import "LockViewDelegate.h" // 遵守协议,用于获知,用户在LockView上画的解锁路径
@interface BeyondViewController ()<LockViewDelegate> @end @implementation BeyondViewController #pragma mark - LockView代理方法
// 用于获知,用户在LockView上画的解锁路径
- (void)lockView:(LockView *)lockView didFinishPath:(NSString *)path
{
[MBProgressHUD showSuccess:path];
NSLog(@"获得用户的手势路径:%@", path);
} @end<span style="font-family:Courier New;color:#393939;"><span style="font-size: 24px; line-height: 26px; background-color: rgb(245, 245, 245);"><strong>
</strong></span></span>

自己定义CircleButton
//
// Circle.m
// 39_触摸解锁
//
// Created by beyond on 14-9-17.
// Copyright (c) 2014年 com.beyond. All rights reserved.
// #import "Circle.h" @implementation Circle - (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// 自己定义方法,初始化
[self setup];
}
return self;
} - (id)initWithCoder:(NSCoder *)aDecoder
{
if (self = [super initWithCoder:aDecoder]) {
// 自己定义方法,初始化
[self setup];
}
return self;
} // 自己定义方法,初始化
- (void)setup
{
// 设置button不可用(不可点击)
self.userInteractionEnabled = NO; // 设置默认的背景图片
[self setBackgroundImage:[UIImage imageNamed:@"gesture_node_normal"] forState:UIControlStateNormal]; // 设置选中时的背景图片(selected)
[self setBackgroundImage:[UIImage imageNamed:@"gesture_node_highlighted"] forState:UIControlStateSelected];
} @end

LockView定义的协议
//
// LockViewDelegate.h
// 39_触摸解锁
//
// Created by beyond on 14-9-17.
// Copyright (c) 2014年 com.beyond. All rights reserved.
// 自己定义的LockView的代理必需 遵守的协议 #import <Foundation/Foundation.h> @class LockView; @protocol LockViewDelegate <NSObject> @optional
// 锁屏手势绘制完毕时,调用本方法,通知外界
- (void)lockView:(LockView *)lockView didFinishPath:(NSString *)path; @end

核心代码,自己定义的LockView
//
// LockView.h
// 39_触摸解锁
//
// Created by beyond on 14-9-17.
// Copyright (c) 2014年 com.beyond. All rights reserved.
// #import <UIKit/UIKit.h>
@protocol LockViewDelegate;
@interface LockView : UIView // 代理,为当前控制器,目的是,解锁手势绘制完毕后,通知它
@property (nonatomic, weak) IBOutlet id<LockViewDelegate> delegate; @end

//
// LockView.m
// 39_触摸解锁
//
// Created by beyond on 14-9-17.
// Copyright (c) 2014年 com.beyond. All rights reserved.
// 重点,核心~~~ #import "LockView.h"
#import "Circle.h"
#import "LockViewDelegate.h" @interface LockView()
// 数组,记住全部的touchMove经过的circle
@property (nonatomic, strong) NSMutableArray *circleArr;
// 手指一直与屏幕保持触摸的点,活动的点,用于绘制最后一个circle的中心到 用户触摸点的线段
@property (nonatomic, assign) CGPoint activePoint;
@end @implementation LockView #pragma mark - 懒载入
// 数组,记住全部的touchMove经过的circle
- (NSMutableArray *)circleArr
{
if (_circleArr == nil) {
_circleArr = [NSMutableArray array];
}
return _circleArr;
}
#pragma mark - 初始化
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// 调用自己定义方法,一次性加入全部的button
[self addAllCircles];
}
return self;
} - (id)initWithCoder:(NSCoder *)aDecoder
{
if (self = [super initWithCoder:aDecoder]){
// 调用自己定义方法,一次性加入全部的button
[self addAllCircles];
}
return self;
}
// 调用自己定义方法,一次性加入全部的button
- (void)addAllCircles
{
for (int index = 0; index<9; index++) {
// 创建自己定义button,绑定tag目的是,将来用于验证锁的顺序
Circle *btn = [Circle buttonWithType:UIButtonTypeCustom];
btn.tag = index;
// 加入button
[self addSubview:btn];
}
}
#pragma mark - 父类方法
// 每加入一个circle,就调整一下全部子控件的frame
- (void)layoutSubviews
{
// 必须先调用父类的方法
[super layoutSubviews];
// 遍历全部的子button,又一次调整frame
for (int i = 0; i<self.subviews.count; i++) {
// 取出button
Circle *btn = self.subviews[i]; // 设置frame
CGFloat btnW = 74;
CGFloat btnH = 74;
// 共三列
int totalColumns = 3;
// 第i个button 所在的列
int col = i % totalColumns;
// 第i个button 所在的行
int row = i / totalColumns;
// 间距均分
CGFloat marginX = (self.frame.size.width - totalColumns * btnW) / (totalColumns + 1);
CGFloat marginY = marginX;
// 设置frame
CGFloat btnX = marginX + col * (btnW + marginX);
CGFloat btnY = row * (btnH + marginY);
btn.frame = CGRectMake(btnX, btnY, btnW, btnH);
}
} #pragma mark - 触摸方法
// 手指按下
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
// 1.必须先清空上一次(手指与屏幕一直接触的点)
self.activePoint = CGPointZero; // 2.调用自己定义方法,获得触摸開始的这个点
CGPoint startPoint = [self pointWithTouches:touches]; // 3.调用自己定义方法,获得触摸到的button(假设有的话)
Circle *btn = [self buttonWithPoint:startPoint]; // 4.设置该被触摸到的button的状态(假设有)
if (btn && btn.selected == NO) {
btn.selected = YES;
// button数组中没有,才要加入到对象数组
[self.circleArr addObject:btn];
} // 5.刷新界面,以下方法会自己主动调用drawRect
[self setNeedsDisplay];
}
// 手指移动(调用频率相当高)
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
// 1.调用自己定义方法,获得触摸过程中的点
CGPoint pos = [self pointWithTouches:touches]; // 2.调用自己定义方法,获得触摸移动时碰到的button(假设有的话)
Circle *btn = [self buttonWithPoint:pos]; // 3.设置该被触摸移动时碰到的button的状态(假设有)
if (btn && btn.selected == NO) {
// 摸到了button
btn.selected = YES;
// button数组中没有,才要加入到对象数组
[self.circleArr addObject:btn];
} else {
// 没有摸到button,就更新activePoint的位置,以便drawRect
self.activePoint = pos;
}
// 4.刷新界面,以下方法会自己主动调用drawRect
[self setNeedsDisplay];
}
// 触摸结束(手抬起了),通知代理,
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
// 1.通知代理
if ([self.delegate respondsToSelector:@selector(lockView:didFinishPath:)]) {
NSMutableString *path = [NSMutableString string];
for (Circle *btn in self.circleArr) {
// tag此时,起到关键作用
[path appendFormat:@"%d", btn.tag];
}
[self.delegate lockView:self didFinishPath:path];
}
// 2.可有可无,清空全部的button选中状态(恢复原样)
[self.circleArr makeObjectsPerformSelector:@selector(setSelected:) withObject:@(NO)]; // 3.清空选中的button对象数组(为下一次手指按下做准备)
[self.circleArr removeAllObjects];
// 4.刷新界面,以下方法会自己主动调用drawRect
[self setNeedsDisplay];
}
// 触摸被打断(相似结束)
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
[self touchesEnded:touches withEvent:event];
} #pragma mark - 抽取的自己定义方法
// 自己定义方法,依据touches集合获得相应的触摸点位置坐标
- (CGPoint)pointWithTouches:(NSSet *)touches
{
UITouch *touch = [touches anyObject];
// 返回手指触摸点在相应view中的坐标
return [touch locationInView:touch.view];
} // 自己定义方法,依据触摸点位置坐标,遍历全部button,获得被碰手指到的button(假设有)
- (Circle *)buttonWithPoint:(CGPoint)point
{
for (Circle *btn in self.subviews) {
// CGFloat wh = 24;
// CGFloat frameX = btn.center.x - wh * 0.5;
// CGFloat frameY = btn.center.y - wh * 0.5;
// if (CGRectContainsPoint(CGRectMake(frameX, frameY, wh, wh), point)) {
if (CGRectContainsPoint(btn.frame, point)) {
return btn;
}
} return nil;
} #pragma mark - 核心~画图
// 最后一步
- (void)drawRect:(CGRect)rect
{
// 假设没有碰到不论什么button,直接返回,不用绘线
if (self.circleArr.count == 0) return; // 1.開始一个贝塞尔路径
UIBezierPath *path = [UIBezierPath bezierPath]; // 2.遍历全部的button,将碰到的button的中心加入到路径中
for (int i = 0; i<self.circleArr.count; i++) {
Circle *btn = self.circleArr[i];
if (i == 0) {
// 设置路径起点
[path moveToPoint:btn.center];
} else {
// 加入到路径
[path addLineToPoint:btn.center];
}
} // 3.连接最后一条,即最后一个碰到的button中心 至 activePoint
if (CGPointEqualToPoint(self.activePoint, CGPointZero) == NO) {
// 必须先进行检測
[path addLineToPoint:self.activePoint];
} // 4.设置画图属性
path.lineWidth = 8;
// 圆接头
path.lineJoinStyle = kCGLineJoinBevel;
// 线条天蓝色
[[UIColor colorWithRed:32/255.0 green:210/255.0 blue:254/255.0 alpha:0.5] set];
// 5.闭合贝塞尔路径
[path stroke];
} @end

storyboard



iOS_39_触摸解锁的更多相关文章

  1. Jimmychoo商城系统总结

    一.需求 1.游戏模块 ①在进入H5之前,首先有一个动态的探照灯的动效,然后由"淡出"效果到H5首页. ②在点击"开始游戏"之后会有一段动画演示游戏内容,然后滑 ...

  2. Quartz2D复习(二) --- 手势解锁

    这次支付宝手机客户端升级,把手势解锁那个功能去掉了,引起很多人的抱怨,觉得少了手势解锁的保护,个人信息容易泄漏了... 那么手势解锁功能是怎么是实现的呢,这里使用Quart2D来简单模拟一下, 先看下 ...

  3. iOS--开发之手势解锁

    本文主要介绍通过手势识别实现手势解锁功能,这个方法被广泛用于手机解锁,密码验证,快捷支付等功能实现.事例效果如下所示. 首先,我们先分析功能的实现过程,首先我们需要先看大致的实现过程: 1.加载九宫格 ...

  4. iOS - TouchLock 手势解锁

    1.手势解锁的创建 代码封装见 QExtension QLockView.h #import <UIKit/UIKit.h> @interface QLockView : UIView / ...

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

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

  6. [iOS UI进阶 - 3.0] 触摸事件的基本处理

    A.需要掌握和练习的 1.介绍事件类型2.通过按钮的事件处理引出view的事件处理3.响应者对象 --> UIResponder --> UIView4.view的拖拽* 实现触摸方法,打 ...

  7. HTML5 Canvas简简单单实现手机九宫格手势密码解锁

    原文:HTML5 Canvas简简单单实现手机九宫格手势密码解锁 早上花了一个半小时写了一个基于HTML Canvas的手势解锁,主要是为了好玩,可能以后会用到. 思路:根据配置计算出九个点的位置,存 ...

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

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

  9. TouchID 指纹解锁

    概述 TouchID 指纹解锁 详细 代码下载:http://www.demodashi.com/demo/10701.html 一.软硬件支持 指纹验证功能的最低硬件支持为iPhone5s, iPa ...

随机推荐

  1. 【转载】Outlook2010 移动数据文件到其它地方

            您可以将数据文件移到计算机的其他文件夹中.移动文件的一个原因在于可使备份更容易并且可以让默认的outlook邮件文件不在存在C盘,导致装系统不见或者文件过大而撑死了C盘.例如,如果数据 ...

  2. 牛客网 牛客小白月赛1 J.おみやげをまらいました

    J.おみやげをまらいました   链接:https://www.nowcoder.com/acm/contest/85/J来源:牛客网     随便写写.   代码: 1 #include<ios ...

  3. 51nod 1105 第K大的数 【双重二分/二分套二分/两数组任意乘积后第K大数】

    1105 第K大的数  基准时间限制:1 秒 空间限制:131072 KB 分值: 40 难度:4级算法题  收藏  关注 数组A和数组B,里面都有n个整数.数组C共有n^2个整数,分别是A[0] * ...

  4. 洛谷—— P1609 最小回文数

    https://www.luogu.org/problemnew/show/1609 题目描述 回文数是从左向右读和从右向左读结果一样的数字串. 例如:121.44 和3是回文数,175和36不是. ...

  5. 关于bug的沟通

    关于BUG的沟通 一个人要去做一件事情,一般来说是按照自己的意愿去做的,如果不是自己想做而是被要求这么做的话,心里一定会留下点不愉快,特别是那种有自信有自己主见的人,比如说开发人员,当测试人员发现一个 ...

  6. Spring Cloud学习总结(非原创)

    文章大纲 一.课程内容总结二.课程学习地址三.学习资料下载四.参考文章 一.课程内容总结   二.课程学习地址 第一天:https://www.jianshu.com/p/a086421f4bfd第二 ...

  7. 网上常用免费webservice_查询(网络复制)

    MP3在线搜索服务 地址:http://www.wopos.com/webservice/song.asmx 介绍: 使用: getMusicList()方法搜索MP3/WMA等音乐文件 多功能条形码 ...

  8. git 服务器搭建,在自己服务器上搭建私有仓库

    创建一个简单的私人Git版本控制服务器,首先得有个服务器(屁话).这种方式适合人比较少的情况,管理不需要很复杂,只要增加几个账号就能搞定. 如下面的情况,有一个服务器,两个客户端. 服务器:Debia ...

  9. http://preshing.com/

    http://preshing.com/ http://mechanical-sympathy.blogspot.com/

  10. 2016.6.20 maven下载与安装步骤

    (1)进入maven官网的下载页面. https://maven.apache.org/download.cgi (2)下载页面中可以看到很多可供下载的链接.gz和zip只是压缩方式的区别,这两个都是 ...