iOS_39_触摸解锁

最终效果图:

控制器:

//
//  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
{
    // 设置按钮不可用(不可点击)
    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) {
        // 调用自定义方法,一次性添加所有的按钮
        [self addAllCircles];
    }
    return self;
}

- (id)initWithCoder:(NSCoder *)aDecoder
{
    if (self = [super initWithCoder:aDecoder]){
        // 调用自定义方法,一次性添加所有的按钮
        [self addAllCircles];
    }
    return self;
}
// 调用自定义方法,一次性添加所有的按钮
- (void)addAllCircles
{
    for (int index = 0; index<9; index++) {
        // 创建自定义按钮,绑定tag目的是,将来用于验证锁的顺序
        Circle *btn = [Circle buttonWithType:UIButtonTypeCustom];
        btn.tag = index;
        // 添加按钮
        [self addSubview:btn];
    }
}
#pragma mark - 父类方法
// 每添加一个circle,就调整一下所有子控件的frame
- (void)layoutSubviews
{
    // 必须先调用父类的方法
    [super layoutSubviews];
    // 遍历所有的子按钮,重新调整frame
    for (int i = 0; i<self.subviews.count; i++) {
        // 取出按钮
        Circle *btn = self.subviews[i];

        // 设置frame
        CGFloat btnW = 74;
        CGFloat btnH = 74;
        // 共三列
        int totalColumns = 3;
        // 第i个按钮 所在的列
        int col = i % totalColumns;
        // 第i个按钮 所在的行
        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.调用自定义方法,获得触摸到的按钮(如果有的话)
    Circle *btn = [self buttonWithPoint:startPoint];

    // 4.设置该被触摸到的按钮的状态(如果有)
    if (btn && btn.selected == NO) {
        btn.selected = YES;
        // 按钮数组中没有,才要添加到对象数组
        [self.circleArr addObject:btn];
    }

    // 5.刷新界面,下面方法会自动调用drawRect
    [self setNeedsDisplay];
}
// 手指移动(调用频率相当高)
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    // 1.调用自定义方法,获得触摸过程中的点
    CGPoint pos = [self pointWithTouches:touches];

    // 2.调用自定义方法,获得触摸移动时碰到的按钮(如果有的话)
    Circle *btn = [self buttonWithPoint:pos];

    // 3.设置该被触摸移动时碰到的按钮的状态(如果有)
    if (btn && btn.selected == NO) {
        // 摸到了按钮
        btn.selected = YES;
        // 按钮数组中没有,才要添加到对象数组
        [self.circleArr addObject:btn];
    } else {
        // 没有摸到按钮,就更新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.可有可无,清空所有的按钮选中状态(恢复原样)
    [self.circleArr makeObjectsPerformSelector:@selector(setSelected:) withObject:@(NO)];

    // 3.清空选中的按钮对象数组(为下一次手指按下做准备)
    [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];
}

// 自定义方法,根据触摸点位置坐标,遍历所有按钮,获得被碰手指到的按钮(如果有)
- (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
{
    // 如果没有碰到任何按钮,直接返回,不用绘线
    if (self.circleArr.count == 0) return;

    // 1.开始一个贝塞尔路径
    UIBezierPath *path = [UIBezierPath bezierPath];

    // 2.遍历所有的按钮,将碰到的按钮的中心添加到路径中
    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.连接最后一条,即最后一个碰到的按钮中心 至 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

时间: 2024-10-17 06:29:38

iOS_39_触摸解锁的相关文章

颠覆想象——vivo Xplay5人性化体验揭秘

3月1日,vivo在水立方发布了全新旗舰产品Xplay5,这款继Xplay3s诞生两年之后推出的全新旗舰产品,无论在配置还是在操控体验方面都带来了颠覆性的革命变化,尤其是其在最新Funtouch 2.5系统中引入的诸多人性化功能,更使得这款手机的体验变得前所未有.笔者有幸近日拿到vivo Xplay5真机,在经过数个礼拜的长时间体验之后,对其中的分屏多任务.程序双开.指纹解锁.轻触指纹拍照.智慧引擎等细节功能有了深刻印象,下面是笔者对这些细分功能进行全面体验之后的札记,以期能对欲购买Xplay5

UI进阶--Quartz2D和触摸事件的简单使用:手势解锁

需求:实现一个简易的手势解锁应用,具体效果如下图所示: 实现步骤: 1.代码创建界面,自定义一个view,设置view的背景,颜色等属性: 2.在自定义的view中,定义2个属性,一个是存储被选中按钮的可变数组,另外一个是最后的触摸点(CGPoint); 3.重写initWithFrame方法,在这里,自定义一个方法给initWithFrame方法调用即可,这个自定义的方法里,初始化9个按钮,设置每个按钮的tag,正常状态下的图片以及选中状态的图片,并设置和用户的交互为NO: 4.在自定义的vi

九点(九宫格)式手势解锁自定义view

周末闲着没事,写了个手势解锁的view,实现起来也蛮快的,半天多一点时间就完事.把源码和资源贴出来,给大家分享,希望对大家有用. 效果,就跟手机上的九点手势解锁一样,上个图吧: 过程嘛感觉确实没啥好讲的了,涉及的知识以前的博客都说过了,无非就是canva,paint,touch事件这些,画画圆圈画画线条,剩下的就是细节处理逻辑了.都在代码里,所以这里就主要是贴资源吧. 这个自定义view就一个类,源码如下: package com.cc.library.view; import android.

iOS开发之手势解锁

本文主要介绍通过手势识别实现手势解锁功能,这个方法被广泛用于手机解锁,密码验证,快捷支付等功能实现.事例效果如下所示. 首先,我们先分析功能的实现过程,首先我们需要先看大致的实现过程: 1.加载九宫格页面 2.实现按钮被点击及滑动过程中按钮状态的改变 3.实现滑动过程中的连线 4.绘制完毕后判定密码是否正确, 5.密码判定后实现跳转. 下面我们就来用代码实现上述五个过程. 1.加载九宫格界面 1.1九宫格内控件的分布 3*3 ,我们可以自定义view(包含3*3个按钮),添加到viewContr

【代码笔记】手势解锁

动画实现解锁-文件目录 ViewController.h文件 //创建自定义的View,遵守协议,设置代理,实现代理方法 1 #import "LYPaintView.h" 2 3 #import "ViewController.h" 4 5 @interface ViewController ()<LYPaintViewDelegate> 6 7 @end 8 9 @implementation ViewController 10 11 - (void

(素材源码)猫猫学IOS(三十五)UI之Quartz2D仿真支付宝手势解锁_代理获得密码。

猫猫分享,必须精品 原创文章,欢迎转载.转载请注明:翟乃玉的博客 地址:http://blog.csdn.net/u013357243?viewmode=contents 源码:http://download.csdn.net/detail/u013357243/8669765 效果: 代码: NYLockView.h // // NYLockView.h // 手势解锁 // // Created by apple on 15-5-6. // Copyright (c) 2015年 znyca

【iOS开发之旅】手势解锁

BOERLockView.h // // BOERLockView.h // BoerScore // // Created by ChenQianPing on 16/2/18. // Copyright © 2016年 boer. All rights reserved. // #import <UIKit/UIKit.h> @class BOERLockView; @protocol BOERLockViewDelegate <NSObject> // 结束手势解锁代理事件

手势解锁

ViewController.m // //  ViewController.m //  6A08.手势解锁 // //  Created by huan on 16/2/1. //  Copyright © 2016年 huanxi. All rights reserved. // #import "ViewController.h" #import "CZLockView.h" @interface ViewController () @end @impleme

手势解锁步骤的基本思路

------------- 基本思路 -------------- - 1. 搭建界面,九宫格算法 - 2. 处理按钮选中状态 - 3. 按钮之间画线 - 4. 手指和按钮之间画线 - 5. 判断解锁密码是否正确 ------------- 基本思路 -------------- 1. 拖拽图片素材 2. 设置控制器 view 的背景色为"HomeButtomBG"图片平铺后的效果 self.view.backgroundColor = [UIColor colorWithPatter