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 手势解锁的更多相关文章

  1. iOS绘制手势解锁密码

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

  2. iOS - TouchLock 手势锁

    1.绘制手势锁 具体实现代码见 GitHub 源码 QExtension QTouchLockView.h @interface QTouchLockView : UIView /// 提示信息框 @ ...

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

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

  4. SJGestureUnlock快速集成手势解锁

    前言:如果页面显示不完整或图片看不了还请移步:简书 SJGestureUnlock.h 常用自定义属性 @interface SJGestureUnlock : UIView @property (n ...

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

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

  6. HTML5实现屏幕手势解锁

    HTML5实现屏幕手势解锁(转载) https://github.com/lvming6816077/H5lockHow to use? <script type="text/java ...

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

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

  8. 点击事件touches与ios的手势UIGestureRecognizer

    .h文件 @property (weak,nonatomic) IBOutlet UILabel *messageLabel;@property (weak,nonatomic) IBOutlet U ...

  9. [BS-25] IOS中手势UIGestureRecognizer概述

    IOS中手势UIGestureRecognizer概述 一.概述 iPhone中处理触摸屏的操作,在3.2之前是主要使用的是由UIResponder而来的如下4种方式: - (void)touches ...

随机推荐

  1. java正则表达式四种常用的处理方式是怎么样呢《匹配、分割、代替、获取》

    java 正则表达式高级篇,介绍四种常用的处理方式:匹配.分割.替代.获取,具体内容如下package test; import java.util.regex.Matcher; import jav ...

  2. session 加入redis的实现代码方式

    session,中文经常翻译为会话,其本来的含义是 指有始有终的一系列动作/消息,比如打电话时从拿起电话拨号到挂断电话这中间的一系列过程可以称之为一个session.有时候我们可以看到这样的话&quo ...

  3. 本人整理的一些PHP常用函数

    <?php //===============================时间日期=============================== //y返回年最后两位,Y年四位数,m月份数字 ...

  4. ACM题目————玩转二叉树

    给定一棵二叉树的中序遍历和前序遍历,请你先将树做个镜面反转,再输出反转后的层序遍历的序列.所谓镜面反转,是指将所有非叶结点的左右孩子对换.这里假设键值都是互不相等的正整数. 输入格式: 输入第一行给出 ...

  5. ACM题目————食物链

    题目描述 Description 动物王国中有三类动物 A,B,C,这三类动物的食物链构成了有趣的环形.A吃B,B吃C,C吃A. 现有N个动物,以1-N编号.每个动物都是A,B,C中的一种,但是我们并 ...

  6. java程序 输入10个数字并求和

    课程作业: 模仿JavaAppArguments.java示例,编写编写一个程序,此程序从命令行接受多个数字,求和之后输出结果. 设计思想: 先从命令行读出数字,然后计算各个数字之和.求出结果. 流程 ...

  7. c#作业

    string a = this.textBox1.Text; // string [] b=a.Split("\r\n".ToCharArray(),StringSplitOpti ...

  8. easyui datebox 只选择年月

    //将日期输入框变为年月的函数方法    var month=0;      $('#effectiveDate').datebox({        onShowPanel: function () ...

  9. UVa 133,发放救济金

    沿用前一个题的思路: 用left记录剩下的点,直到全部选完. 这里我的问题是,我一直pos = (pos + f + n)%n,这里的问题是对于B点来说,开始的位置是1,就成了(1+(-1) +n) ...

  10. 什么是RAW数据?

    现在数码照片的存储格式,以及在网络上应用的最普遍的图片格式就是JPEG格式了(Joint Photographic Expert Group).但是作为一种有损的图像压缩格式(现在也有少数数码相机提供 ...