iOS - TouchLock 手势锁
1、绘制手势锁
具体实现代码见 GitHub 源码 QExtension
QTouchLockView.h
@interface QTouchLockView : UIView /// 提示信息框
@property (nonatomic, strong) UILabel *alertLabel; /**
* 创建手势锁视图控件,获取滑动手势结果
*
* @param frame 手势锁视图控件的位置尺寸
* @param result 滑动手势结果,YES 成功,NO 失败
*
* @return 手势锁视图控件
*/
+ (instancetype)q_touchLockViewWithFrame:(CGRect)frame
pathResult:(void (^)(BOOL isSucceed, NSString *result))result; @end
QTouchLockView.m
#import "NSString+Hash.h" @interface QTouchLockView () /// 存放选中的按钮
@property (nonatomic, strong) NSMutableArray *selectedArray; /// 当前被选中的按钮
@property (nonatomic, assign) CGPoint currentPoint; /// 滑动手势结果
@property (nonatomic, copy) void (^resultBlock)(BOOL, NSString *); @end @implementation QTouchLockView /// 创建手势锁界面,获取滑动结果
+ (instancetype)q_touchLockViewWithFrame:(CGRect)frame
pathResult:(void (^)(BOOL isSucceed, NSString *result))result { QTouchLockView *touchLockView = [[self alloc] init]; CGRect tmpFrame = frame;
tmpFrame.size.height = frame.size.width; touchLockView.frame = tmpFrame;
touchLockView.resultBlock = result; return touchLockView;
} /// 初始化界面
- (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { self.backgroundColor = [UIColor whiteColor]; // 添加提示信息框
self.alertLabel = [[UILabel alloc] init];
self.alertLabel.textAlignment = NSTextAlignmentCenter;
self.alertLabel.textColor = [UIColor redColor];
self.alertLabel.backgroundColor = [UIColor clearColor];
self.alertLabel.numberOfLines = 1;
self.alertLabel.adjustsFontSizeToFitWidth = YES;
[self addSubview:self.alertLabel]; // 添加按钮
for (int i = 0; i < 9; i++){ UIButton *btn = [[UIButton alloc] init]; NSString *bundlePath = [[[NSBundle mainBundle] resourcePath]
stringByAppendingPathComponent:@"QTouchLockView.bundle"]; UIImage *normalImage = [UIImage imageWithContentsOfFile:
[bundlePath stringByAppendingPathComponent:@"gesture_node_normal"]];
UIImage *selectedImage = [UIImage imageWithContentsOfFile:
[bundlePath stringByAppendingPathComponent:@"gesture_node_selected"]];
UIImage *highlightedImage = [UIImage imageWithContentsOfFile:
[bundlePath stringByAppendingPathComponent:@"gesture_node_highlighted"]]; [btn setBackgroundImage:normalImage forState:UIControlStateNormal];
[btn setBackgroundImage:selectedImage forState:UIControlStateSelected];
[btn setBackgroundImage:highlightedImage forState:UIControlStateHighlighted]; // 设置 tag 值,设置按钮对应的密码值
btn.tag = i + 1; // 关闭按钮的交互,响应触摸事件
btn.userInteractionEnabled = NO; [self addSubview:btn];
}
}
return self;
} /// 布局控件
- (void)layoutSubviews {
[super layoutSubviews]; // 设置按钮的 frame
for (int i = 0; i < self.subviews.count - 1; i++) { // 列数
NSInteger cols = 3; // 设置按钮尺寸
CGFloat W = self.bounds.size.width;
CGFloat H = self.bounds.size.height;
CGFloat btnW = W / 5;
CGFloat btnH = H / 5; // 计算按钮的 x 坐标值
NSUInteger col = i % cols;
CGFloat btnX = col * btnW * 2; // 计算按钮的 y 坐标值
NSUInteger row = i / cols;
CGFloat btnY = row * btnH * 2; // 设置按钮的 frame
UIButton *btn = self.subviews[i + 1];
btn.frame = CGRectMake(btnX, btnY, btnW, btnH);
} // 设置提示信息框的 frame
self.alertLabel.frame = CGRectMake(0, -50, self.bounds.size.width, 30);
} /// 触摸开始
- (void)touchesBegan:(NSSet *)touches withEvent:(nullable UIEvent *)event { // 获取触摸起始点位置
CGPoint startPoint = [touches.anyObject locationInView:self]; // 获取其 button
UIButton *button = nil;
for (UIButton *btn in self.subviews) { // 设置触摸按钮的灵敏度
CGRect frame = btn.frame;
CGRect tmpFrame = CGRectMake(frame.origin.x + frame.size.width / 4,
frame.origin.y + frame.size.height / 4,
frame.size.width / 2,
frame.size.height / 2); // 判断某点在不在其 frame 上
if (CGRectContainsPoint(tmpFrame, startPoint)) {
button = btn;
}
} // 选中此 button
if (button && button.selected == NO) {
button.selected = YES;
[self.selectedArray addObject:button];
}
} /// 触摸移动
- (void)touchesMoved:(NSSet *)touches withEvent:(nullable UIEvent *)event { // 获取触摸点位置
CGPoint touchPoint = [touches.anyObject locationInView:self]; // 获取其 button
UIButton *button = nil;
for (UIButton *btn in self.subviews) { // 设置触摸按钮的灵敏度
CGRect frame = btn.frame;
CGRect tmpFrame = CGRectMake(frame.origin.x + frame.size.width / 4,
frame.origin.y + frame.size.height / 4,
frame.size.width / 2,
frame.size.height / 2); // 判断某点在不在其 frame 上
if (CGRectContainsPoint(tmpFrame, touchPoint)) {
button = btn;
}
} // 选中此 button
if (button && button.selected == NO) {
button.selected = YES;
[self.selectedArray addObject:button];
} else {
self.currentPoint = touchPoint;
} // 刷新视图
[self setNeedsDisplay];
} /// 触摸结束
- (void)touchesEnded:(NSSet *)touches withEvent:(nullable UIEvent *)event { if (self.selectedArray.count < 4) { // 触摸点数过少
if (self.resultBlock) {
self.resultBlock(NO, @"请至少连续连接四个点");
} for (UIButton *btn in self.selectedArray) { btn.highlighted = YES;
btn.selected = NO;
} // 延迟
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,
(int64_t)(0.5 * NSEC_PER_SEC)),
dispatch_get_main_queue(), ^{ [self clearPath];
}); } else { // 触摸完成
if (self.resultBlock) { // 获取触摸结果
NSMutableString *path = [NSMutableString string];
for (UIButton *btn in self.selectedArray) {
[path appendFormat:@"%ld", btn.tag];
} // 对滑动获取的密码值进行 MD5 加密
NSString *md5Path = [path q_md5String]; self.resultBlock(YES, md5Path);
} [self clearPath];
}
} /// 触摸取消
- (void)touchesCancelled:(NSSet *)touches withEvent:(nullable UIEvent *)event { [self touchesEnded:touches withEvent:event];
} /// 绘制贝塞尔连接线
- (void)drawRect:(CGRect)rect { if (self.selectedArray.count == 0) {
return;
} UIBezierPath *path = [UIBezierPath bezierPath];
path.lineWidth = 5;
path.lineJoinStyle = kCGLineCapRound;
[[UIColor colorWithRed:1 green:0 blue:0 alpha:0.5] set]; for (int i = 0; i < self.selectedArray.count; i++) { UIButton *btn = self.selectedArray[i]; // 如果是第一个按钮,则将其曲线的起点放在其按钮上,否则则进行连线
if (i == 0) {
[path moveToPoint:btn.center];
} else {
[path addLineToPoint:btn.center];
}
} // 如果不满足上述条件,按钮不存在则连接到临时点
[path addLineToPoint:self.currentPoint];
[path stroke];
} /// 清除连接线
- (void)clearPath { // 取消选中按钮
for (UIButton *btn in self.selectedArray) {
btn.highlighted = NO;
btn.selected = NO;
} // 清空选中按钮
[self.selectedArray removeAllObjects]; // 刷新视图
[self setNeedsDisplay];
} /// 懒加载
- (NSMutableArray *)selectedArray {
if (_selectedArray == nil) {
_selectedArray = [NSMutableArray array];
}
return _selectedArray;
} @end
ViewController.m
// 设置 frame
CGFloat margin = 50;
CGFloat width = self.view.bounds.size.width - margin * 2;
CGRect frame = CGRectMake(margin, 200, width, width); // 创建手势锁视图界面,获取滑动结果
QTouchLockView *touchLockView = [QTouchLockView q_touchLockViewWithFrame:frame
pathResult:^(BOOL isSucceed, NSString * _Nonnull result) { // 处理手势触摸结果
[self dealTouchResult:result isSucceed:isSucceed];
}]; [self.view addSubview:touchLockView]; - (void)dealTouchResult:(NSString *)result isSucceed:(BOOL)isSucceed { // 处理手势触摸结果 if (isSucceed) { // 判读密码是否存在
NSUserDefaults *df = [NSUserDefaults standardUserDefaults]; if ([df objectForKey:@"touchLock"] == nil) { // 设置手势锁 [self.passWordArrM addObject:result]; if (self.passWordArrM.count == 1) {
self.touchLockView.alertLabel.text = @"请再设置一次";
} if (self.passWordArrM.count == 2) {
if ([self.passWordArrM[0] isEqualToString:self.passWordArrM[1]]) { // 存储密码
[df setValue:self.passWordArrM[0] forKey:@"touchLock"];
[df synchronize]; self.touchLockView.alertLabel.text = @"手势密码设置成功"; } else { // 两次滑动结果不一致
[self.passWordArrM removeAllObjects]; self.touchLockView.alertLabel.text = @"两次滑动的结果不一致,请重新设置";
}
} } else { // 解锁 if ([result isEqualToString:[df objectForKey:@"touchLock"] ]) {
self.touchLockView.alertLabel.text = @"解锁成功";
} else {
self.touchLockView.alertLabel.text = @"密码不正确,请重试";
}
} } else { // 滑动点数过少
self.touchLockView.alertLabel.text = result;
}
}
效果

iOS - TouchLock 手势锁的更多相关文章
- iOS - TouchLock 手势解锁
1.手势解锁的创建 代码封装见 QExtension QLockView.h #import <UIKit/UIKit.h> @interface QLockView : UIView / ...
- 在iOS上增加手势锁屏、解锁功能
在iOS上增加手势锁屏.解锁功能 在一些涉及个人隐私的场景下,尤其是当移动设备包含太多私密信息时,为用户的安全考虑是有必要的. 桌面版的QQ在很多年前就考虑到用户离开电脑后隐私泄露的危险,提供了“离开 ...
- 谈谈iOS中的锁
1 前言 近日工作不是太忙,刚好有时间了解一些其他东西,本来打算今天上午去体检,但是看看天气还是明天再去吧,也有很大一个原因:就是周六没有预约上!闲话少说,这里简单对锁来个简单介绍分享. 2 目录 第 ...
- 点击事件touches与ios的手势UIGestureRecognizer
.h文件 @property (weak,nonatomic) IBOutlet UILabel *messageLabel;@property (weak,nonatomic) IBOutlet U ...
- Android手势锁实现
最终效果如下 整体思路 a.自定义了一个RelativeLayout(GestureLockViewGroup)在里面会根据传入的每行的个数,生成多个GestureLockView(就是上面一个个小圈 ...
- [BS-25] IOS中手势UIGestureRecognizer概述
IOS中手势UIGestureRecognizer概述 一.概述 iPhone中处理触摸屏的操作,在3.2之前是主要使用的是由UIResponder而来的如下4种方式: - (void)touches ...
- Android 手势锁的实现 为了让自己的应用程序的安全,现在
转载请注明出处:http://blog.csdn.net/lmj623565791/article/details/36236113 今天偶遇以github上gesturelock关于手势锁的一个样例 ...
- IOS各种手势操作实例
先看下效果 手势相关的介绍 IOS中手势操作一般是 UIGestureRecognizer 类的几个手势子类去实现,一般我们用到的手势就这么5种: 1.点击 UITapGestureRecogniz ...
- Android 手势锁的实现 让自己的应用更加安全吧
转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/36236113 今天偶遇以github上gesturelock关于手势锁的一个例子 ...
随机推荐
- C语言:通过函数指针来完成两个数的加减乘除(函数指针当做参数使用)
// // main.c // Function_pointer // // Created by mac on 15/8/2. // Copyright (c) 2015年. All rig ...
- 树状数组(Binary Indexed Tree) 总结
1.“树状数组”数据结构的一种应用 对含有n个元素的数组(a[1],...,a[k],...,a[n]): (1)求出第i个到第j个元素的和,sum=a[i]+...+a[j]. 进行j-i+1次加法 ...
- ubuntu下用户的创建、修改
一.1.添加用户 (1)创建一个新的用户username #sudo useradd username (2)设置用户username 的密码 #sudo passwd username 2.添加用户 ...
- [leetcode]Convert Sorted List to Binary Search Tree @ Python
原题地址:http://oj.leetcode.com/problems/convert-sorted-list-to-binary-search-tree/ 题意:将一条排序好的链表转换为二叉查找树 ...
- 浅谈Jquery中的bind()、live()、delegate()、on()绑定事件方式
一.on(),live(),bind() on() 为指定的元素,添加一个或多个事件处理程序,并规定当这些事件发生时运行的函数.使用 on() 方法的事件处理程序适用于当前或未来的元素(比如由脚本创建 ...
- 【HowTo ML】分类问题->神经网络入门
非线性分类器(Non-linear hypotheses) 为什么使用非线性分类器 我们举几个栗子: 假如我们有一个数据空间如左上角坐标系所看到的,那么我们要的模型须要如右边公式所看到的的预測函数. ...
- 在Linux上自动调整屏幕亮度保护眼睛
导读 Lightbot当你开始在计算机前花费大量时间的时候,问题自然开始显现.这健康吗?怎样才能舒缓我眼睛的压力呢?为什么光线灼烧着我?尽管解答这些问题的研究仍然在不断进行着,许多程序员已经采用了一些 ...
- (https专业版)2018年1月5日高仿互站仿友价T5虚拟交易+实物交易商城-站长交易源码送手机版程序10套模版+首页微信登陆+头部下拉导航
(https专业版)2018年1月5日高仿互站仿友价T5虚拟交易+实物交易商城-站长交易源码送手机版程序10套模版+首页微信登陆+头部下拉导航 首页支持微信登陆,只有第8套模板支持(endv模板),后 ...
- 【Javascript Demo】遮罩层和弹出层简单实现
最近纠结于遮罩层和弹出层的实现,终于搞定了个简单的版本.示例和代码如下,点击按钮可以看到效果: 1.示例: 2.代码: <!DOCTYPE html PUBLIC "-//W3C//D ...
- 12款程序员们最爱的Bootstrap模板
如果你还没有开始使用Bootstrap模板,那你可真是有够OUT,这是一个帮助你快速开发的工具,Bootstrap是基于jQuery框架开发的,它在jQuery框架的基础上进行了更为个性化和人性化的完 ...