年年有"余"

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 6997|回复: 1

一行代码搞定iOS手势解锁功能

[复制链接]
  • TA的每日心情
    奋斗
    2022-12-13 21:26
  • 签到天数: 371 天

    [LV.9]以坛为家II

    发表于 2014-12-29 09:22:48 | 显示全部楼层 |阅读模式
    1、有图有真相

    iOS Simulator Screen Shot 2014年12月27日 下午9.46.46.png

    2、设计思路
    2.1、以屏幕宽度为边长创建一个正方形View;
    2.2、一个for循环创建9个按钮并自动布局;
    2.3、监听该view的触摸事件,触摸区域落在某按钮区域则按钮发光
    2.4、记录发光的按钮,输出按钮顺序(可以在for循环创建按钮时给按钮做tag标记,这样就有对应关系了,从而把按钮转换成字符串密码)

    3、代码示例
    SAScreenLockView.h
    [Objective-C] 纯文本查看 复制代码
    //
    //  SAScreenLockView.h
    //  SAScreenLock
    //
    //  Created by 余西安 on 14/12/27.
    //  Copyright (c) 2014年 Sian. All rights reserved.
    //
    
    #import <UIKit/UIKit.h>
    
    /***************代理协议***************/
    
    @class SAScreenLockView;
    
    @protocol SAScreenLockViewDelegate <NSObject>
    
    - (void)screenLock:(SAScreenLockView *)screenLockView didFinishPaht:(NSNumber *)path;
    
    @end
    
    /***************圆圈控件***************/
    
    @interface SACircle : UIButton
    
    @end
    
    /***************解锁视图***************/
    
    @interface SAScreenLockView : UIView
    
    @property (nonatomic, weak) id<SAScreenLockViewDelegate> delegate;
    
    - (id)initWithDelegate:(id<SAScreenLockViewDelegate>)delegate;
    
    @end
    SAScreenLockView.m
    [Objective-C] 纯文本查看 复制代码
    //
    //  SAScreenLockView.m
    //  SAScreenLock
    //
    //  Created by 余西安 on 14/12/27.
    //  Copyright (c) 2014年 Sian. All rights reserved.
    //
    
    #import "SAScreenLockView.h"
    
    /*********************圆圈控件*********************/
    
    @implementation SACircle
    
    - (id)initWithCoder:(NSCoder *)aDecoder
    {
        if (self = [super initWithCoder:aDecoder]) {
            [self setup];
        }
        return self;
    }
    
    - (id)initWithFrame:(CGRect)frame
    {
        self = [super initWithFrame:frame];
        if (self) {
            [self setup];
        }
        return self;
    }
    
    - (void)setup
    {
        self.userInteractionEnabled = NO;
        UIImage *normal = [UIImage imageNamed:@"gesture_node_normal.png"];
        UIImage *selected = [UIImage imageNamed:@"gesture_node_highlighted"];
        [self setImage:normal forState:UIControlStateNormal];
        [self setImage:selected forState:UIControlStateSelected];
    }
    @end
    
    /*********************解锁视图*********************/
    
    @interface SAScreenLockView ()
    
    @property (nonatomic, strong) NSMutableArray *circles;
    
    @property (nonatomic, assign) CGPoint        position;
    
    @end
    
    @implementation SAScreenLockView
    
    #pragma mark - 初始化方法
    - (id)initWithDelegate:(id<SAScreenLockViewDelegate>)delegate
    {
        if (self = [super init]) {
            self.delegate = delegate;
        }
        return self;
    }
    // xib创建时调用
    - (id)initWithCoder:(NSCoder *)aDecoder
    {
        if (self = [super initWithCoder:aDecoder]) {
            [self setup];
        }
        return self;
    }
    // 代码创建时调用
    - (id)initWithFrame:(CGRect)frame
    {
        self = [super initWithFrame:frame];
        if (self) {
            [self setup];
        }
        return self;
    }
    // 初始化9个子控件
    - (void)setup
    {
        self.backgroundColor = [UIColor clearColor];
        CGFloat width = [[UIScreen mainScreen] bounds].size.width;
        self.frame = (CGRect){CGPointZero, width, width};
        for (int i = 0; i < 9; i++) {
            SACircle *circle = [SACircle buttonWithType:UIButtonTypeCustom];
            circle.tag = i + 1;
            [self addSubview:circle];
        }
    }
    // 被选中的子控件
    - (NSMutableArray *)circles
    {
        if (_circles == nil){
            _circles = [NSMutableArray array];
        }
        return _circles;
    }
    // 子控件位置调整
    - (void)layoutSubviews
    {
        NSInteger columns = 3;
        CGFloat width = self.frame.size.width;
        CGFloat dimeter = 64.0f;
        CGFloat margic = (width - dimeter * columns) / (columns + 1);
        for (SACircle *circle in self.subviews) {
            CGFloat x = (circle.tag - 1) % columns * (dimeter + margic) + margic;
            CGFloat y = (circle.tag - 1) / columns * (dimeter + margic);
            CGFloat w = dimeter;
            CGFloat h = dimeter;
            circle.frame = (CGRect){x, y, w, h};
        }
        CGRect rect = self.frame;
        rect.size.height = dimeter * 3 + margic * 2;
        self.frame = rect;
    }
    
    #pragma mark - 触摸交互事件处理
    - (CGPoint)pointWithTouch:(NSSet *)touches
    {
        UITouch *touch = [touches anyObject];
        return [touch locationInView:self];
    }
    
    - (SACircle *)circleWithTouches:(NSSet *)touches
    {
        CGPoint pos = [self pointWithTouch:touches];
        // 判断当前触摸位置是否进入9个圆圈内
        for (SACircle *circle in self.subviews) {
            CGRect touchArea = circle.frame;
            CGFloat w = touchArea.size.width;
            touchArea.origin.x += w / 4;
            touchArea.origin.y += w / 4;
            touchArea.size.width -= w / 2;
            touchArea.size.height -= w / 2;
            if (CGRectContainsPoint(touchArea, pos)){
                return circle;
            }
        }
        return nil;
    }
    
    - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
    {
        self.position = CGPointZero;
        SACircle *circle = [self circleWithTouches:touches];
        // 如果进入圆圈内并且当前圆圈未被选中则加入到选中数组
        if (circle && !circle.selected){
            circle.selected = YES;
            [self.circles addObject:circle];
        }
        [self setNeedsDisplay];
    }
    
    - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
    {
        self.position = [self pointWithTouch:touches];
        SACircle *circle = [self circleWithTouches:touches];
        // 如果进入圆圈内并且当前圆圈未被选中则加入到选中数组
        if (circle && !circle.selected){
            circle.selected = YES;
            [self.circles addObject:circle];
        }
        [self setNeedsDisplay];
    }
    
    - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
    {
        NSMutableString *path = [NSMutableString string];
        for (SACircle *circle in self.circles) {
            circle.selected = NO;
            [path appendFormat:@"%d", (int)circle.tag];
        }
        // 当选中的圆圈不为空,并且代理有实现代理方法时通知代理
        if ([self.delegate respondsToSelector:@selector(screenLock:didFinishPaht:)] && self.circles.count)
            [self.delegate screenLock:self didFinishPaht:@([path longLongValue])];
        
        [self.circles removeAllObjects];
        [self setNeedsDisplay];
    }
    
    - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
    {
        [self touchesEnded:touches withEvent:event];
    }
    
    #pragma mark - 视图绘制方法
    - (void)drawRect:(CGRect)rect
    {
        if (self.circles.count == 0) return;
        UIBezierPath *path = [UIBezierPath bezierPath];
        path.lineWidth = 8;
        path.lineCapStyle = kCGLineCapRound;
        path.lineJoinStyle = kCGLineJoinRound;
        for (int i = 0; i < self.circles.count; i++) {
            SACircle *circle = self.circles[i];
            if (i == 0) {
                [path moveToPoint:circle.center];
            } else {
                [path addLineToPoint:circle.center];
            }
        }
        if (!CGPointEqualToPoint(self.position, CGPointZero))
            [path addLineToPoint:self.position];
        [[UIColor colorWithRed:122/255.0 green:214/255.0 blue:250/255.0 alpha:0.7] set];
        [path stroke];
    }
    
    @end
    

    4、Demo下载:
    游客,如果您要查看本帖隐藏内容请回复

  • TA的每日心情
    犯困
    2015-1-11 14:36
  • 签到天数: 5 天

    [LV.2]偶尔看看I

    发表于 2015-6-26 16:02:22 | 显示全部楼层
    感谢楼主的分享
    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    手机版|小黑屋|Archiver|iOS开发笔记 ( 湘ICP备14010846号 )

    GMT+8, 2024-4-24 07:34 , Processed in 0.046694 second(s), 21 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表