九宫格手势密码

九宫格手势密码_第1张图片
Lock.png

上图是QQ的解锁画面,不知道这样的设计是故意为之还是疏忽,允许隔断连线确实增加了密码复杂性,但是在QQ这里出现了有时候快速划过连不上的问题。。。

所以最好还是采用不允许隔点连线为好。

首先画圆圈

DDYCircleView.h

#import 

/** 圆的状态 */
typedef NS_ENUM(NSInteger, DDYCircleViewState) {
    DDYCircleViewStateNormal             = 1,
    DDYCircleViewStateSelected           = 2,
    DDYCircleViewStateError              = 3,
    DDYCircleViewStateLastOneSelected    = 4,
    DDYCircleViewStateLastOneError       = 5,
};

/** 圆的用途 */
typedef NS_ENUM(NSInteger, DDYCircleViewType) {
    DDYCircleViewTypeInfo                = 1,
    DDYCircleViewTypeGesture             = 2,
};

@interface DDYCircleView : UIView

/** 所处状态 */
@property (nonatomic, assign) DDYCircleViewState state;
/** 类型 */
@property (nonatomic, assign) DDYCircleViewType type;
/** 是否有箭头 默认YES */
@property (nonatomic, assign) BOOL arrow;
/** 角度 */
@property (nonatomic, assign) CGFloat angle;
/** 初始化 */
+ (instancetype)circleView;

@end

DDYCircleView.m

#import "DDYCircleView.h"

@implementation DDYCircleView

+ (instancetype)circleView {
    return [[self alloc] init];
}

- (instancetype)init {
    if (self = [super init]) {
        self.backgroundColor = lockViewBgColor;
    }
    return self;
}

- (void)drawRect:(CGRect)rect {
    
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    // 上下文旋转
    [self tansformCtx:ctx rect:rect];
    // 画外空心圆
    [self drawOutCircleWithCtx:ctx rect:rect];
    // 画内实心圆
    [self drawInCircleWithCtx:ctx rect:rect];
    // 画三角形
    [self drawTrangleWithCtx:ctx rect:rect];
}

#pragma mark 上下文旋转
- (void)tansformCtx:(CGContextRef)ctx rect:(CGRect)rect {
    CGFloat translateXY = rect.size.width*.5f;
    CGContextTranslateCTM(ctx, translateXY, translateXY);
    CGContextRotateCTM(ctx, self.angle);
    CGContextTranslateCTM(ctx, -translateXY, -translateXY);
}

#pragma mark 画外空心圆
- (void)drawOutCircleWithCtx:(CGContextRef)ctx rect:(CGRect)rect {
    CGRect circleRect = DDYRect(outCircleWidth, outCircleWidth, rect.size.width-2*outCircleWidth, rect.size.height-2*outCircleWidth);
    CGMutablePathRef circlePath = CGPathCreateMutable();
    CGPathAddEllipseInRect(circlePath, NULL, circleRect);
    CGContextAddPath(ctx, circlePath);
    [[self outCircleColor] set];
    CGContextSetLineWidth(ctx, outCircleWidth);
    CGContextStrokePath(ctx);
    CGPathRelease(circlePath);
}

#pragma mark 画内实心圆
- (void)drawInCircleWithCtx:(CGContextRef)ctx rect:(CGRect)rect {
    CGFloat radio = (self.type == DDYCircleViewTypeGesture) ? circleRadio : 1;
    CGFloat circleX = rect.size.width/2 * (1-radio) + outCircleWidth;
    CGFloat circleY = rect.size.height/2 * (1-radio) + outCircleWidth;
    CGFloat circleW = rect.size.width*radio - outCircleWidth*2;
    CGFloat circleH = rect.size.height*radio - outCircleWidth*2;
    CGMutablePathRef circlePath = CGPathCreateMutable();
    CGPathAddEllipseInRect(circlePath, NULL, CGRectMake(circleX, circleY, circleW, circleH));
    [[self inCircleColor] set];
    CGContextAddPath(ctx, circlePath);
    CGContextFillPath(ctx);
    CGPathRelease(circlePath);
}

#pragma mark 画三角形
- (void)drawTrangleWithCtx:(CGContextRef)ctx rect:(CGRect)rect {
    if (self.arrow) {
        CGPoint topPoint = CGPointMake(rect.size.width/2, 10);
        CGMutablePathRef trianglePath = CGPathCreateMutable();
        CGPathMoveToPoint(trianglePath, NULL, topPoint.x, topPoint.y);
        CGPathAddLineToPoint(trianglePath, NULL, topPoint.x - trangleLength/2, topPoint.y + trangleLength/2);
        CGPathAddLineToPoint(trianglePath, NULL, topPoint.x + trangleLength/2, topPoint.y + trangleLength/2);
        CGContextAddPath(ctx, trianglePath);
        [[self trangleColor] set];
        CGContextFillPath(ctx);
        CGPathRelease(trianglePath);
    }
}

#pragma mark 外圆颜色
- (UIColor *)outCircleColor {
    UIColor *color;
    switch (self.state) {
        case DDYCircleViewStateNormal:
            color = outCircleNormalColor;
            break;
        case DDYCircleViewStateSelected:
            color = outCircleSelectedColor;
            break;
        case DDYCircleViewStateError:
            color = outCircleErrorColor;
            break;
        case DDYCircleViewStateLastOneSelected:
            color = outCircleSelectedColor;
            break;
        case DDYCircleViewStateLastOneError:
            color = outCircleErrorColor;
            break;
        default:
            color = outCircleNormalColor;
            break;
    }
    return color;
}

#pragma mark 内圆颜色
- (UIColor *)inCircleColor {
    UIColor *color;
    switch (self.state) {
        case DDYCircleViewStateNormal:
            color = inCircleNormalColor;
            break;
        case DDYCircleViewStateSelected:
            color = inCircleSelectedColor;
            break;
        case DDYCircleViewStateError:
            color = inCircleErrorColor;
            break;
        case DDYCircleViewStateLastOneSelected:
            color = inCircleSelectedColor;
            break;
        case DDYCircleViewStateLastOneError:
            color = inCircleErrorColor;
            break;
        default:
            color = inCircleNormalColor;
            break;
    }
    return color;
}

#pragma mark 三角颜色
- (UIColor *)trangleColor {
    UIColor *color;
    switch (self.state) {
        case DDYCircleViewStateNormal:
            color = trangleNormalColor;
            break;
        case DDYCircleViewStateSelected:
            color = trangleSelectedColor;
            break;
        case DDYCircleViewStateError:
            color = trangleErrorColor;
            break;
        case DDYCircleViewStateLastOneSelected:
            color = trangleSelectedColor;
            break;
        case DDYCircleViewStateLastOneError:
            color = trangleErrorColor;
            break;
        default:
            color = trangleNormalColor;
            break;
    }
    return color;
}

#pragma mark 角度set方法
- (void)setAngle:(CGFloat)angle {
    _angle = angle;
    [self setNeedsDisplay];
}

#pragma mark 状态set方法
- (void)setState:(DDYCircleViewState)state {
    _state = state;
    [self setNeedsDisplay];
}

@end

其次将上面的圆圈画成九宫格,形成手势区域

DDYLockView.h

#import 

@class  DDYLockView;

typedef NS_ENUM(NSInteger, DDYLockViewType) {
    DDYLockViewTypeSetting = 1, // 设置手势密码
    DDYLockViewTypeLogin   = 2, // 登录手势密码
    DDYLockViewTypeVerify  = 3, // 验证手势密码
};

typedef NS_ENUM(NSInteger, DDYLockViewState) {
    DDYLockViewStateLess        = 1,    // 连线个数少于最小值(设置)
    DDYLockViewStateFirstFinish = 2,    // 提示再次绘制以确认(设置)
    DDYLockViewStateSecondFinish= 3,    // 两次绘制一致可保存(设置)
    DDYLockViewStateSecondError = 4,    // 两次绘制路径不一致(设置)
    DDYLockViewStateLoginFinish = 5,    // 手势密码登录成功(登录)
    DDYLockViewStateLoginError  = 6,    // 手势密码登录失败(登录)
    DDYLockViewStateVerifyFinish= 7,    // 修改密码验证成功(验证)
    DDYLockViewStateVerifyError = 8,    // 修改密码验证失败(验证)
    
};

//--------------------------- delegate ---------------------------//
@protocol DDYLockViewDelegate 

- (void)lockView:(DDYLockView *)lockView state:(DDYLockViewState)state;

@end

//--------------------------- InfoView ---------------------------//
@interface DDYLockInfoView : UIView

+ (instancetype)infoViewWithFrame:(CGRect)frame;

@end

//--------------------------- lockView ---------------------------//
@interface DDYLockView : UIView

/** 是否裁剪 默认YES */
@property (nonatomic, assign) BOOL clip;
/** 是否有箭头 默认YES */
@property (nonatomic, assign) BOOL arrow;
/** 解锁类型 */
@property (nonatomic, assign) DDYLockViewType type;
/** 代理 */
@property (nonatomic, weak) id delegate;
/** 初始化 */
+ (instancetype)lockViewWithType:(DDYLockViewType)type;

+ (instancetype)lockViewWithType:(DDYLockViewType)type clip:(BOOL)clip arrow:(BOOL)arrow;

- (instancetype)initWithType:(DDYLockViewType)type clip:(BOOL)clip arrow:(BOOL)arrow;

@end

DDYLockView.m

#import "DDYLockView.h"

//--------------------------- InfoView ---------------------------//
@implementation DDYLockInfoView

+ (instancetype)infoViewWithFrame:(CGRect)frame {
    return [[self alloc] initWithFrame:frame];
}

- (instancetype)initWithFrame:(CGRect)frame {
    if (self = [super initWithFrame:frame]) {
        self.backgroundColor = circleBgColor;
        for (int i = 0; i < 9; i++) {
            DDYCircleView *circle = [DDYCircleView circleView];
            circle.type = DDYCircleViewTypeInfo;
            [self addSubview:circle];
        }
    }
    return self;
}

- (void)layoutSubviews {
    [super layoutSubviews];
    CGFloat itemViewWH = circleInfoRadius * 2;
    CGFloat itemMargin = (self.ddy_w - 3*itemViewWH) / 3.f;
    // 九宫格
    [self.subviews enumerateObjectsUsingBlock:^(DDYCircleView *circle, NSUInteger idx, BOOL *stop) {
        NSUInteger row = idx % 3;
        NSUInteger col = idx / 3;
        CGFloat x = itemMargin*row + row*itemViewWH + itemMargin/2;
        CGFloat y = itemMargin*col + col*itemViewWH + itemMargin/2;
        circle.tag = idx + 1;
        circle.frame = DDYRect(x, y, itemViewWH, itemViewWH);
    }];
}

@end

//--------------------------- lockView ---------------------------//
@interface DDYLockView ()
/** 选中的圆数组 */
@property (nonatomic, strong) NSMutableArray *selectedCircleArray;
/** 当前点位 */
@property (nonatomic, assign) CGPoint currentPoint;
/** 数组清空标识 */
@property (nonatomic, assign) BOOL isCleaned;

@end

@implementation DDYLockView

#pragma mark setter/getter
#pragma mark 设置箭头
- (void)setArrow:(BOOL)arrow {
    _arrow = arrow;
    // 遍历子控件,改变其是否有箭头
    [self.subviews enumerateObjectsUsingBlock:^(DDYCircleView *circle, NSUInteger idx, BOOL *stop) {
        [circle setArrow:arrow];
    }];
}

- (NSMutableArray *)selectedCircleArray {
    if (!_selectedCircleArray) {
        _selectedCircleArray = [NSMutableArray array];
    }
    return _selectedCircleArray;
}

#pragma mark - 初始化
#pragma mark 类方法初始化,默认裁剪有箭头
+ (instancetype)lockViewWithType:(DDYLockViewType)type {
    return [[self alloc] initWithType:type clip:YES arrow:YES];
}

+ (instancetype)lockViewWithType:(DDYLockViewType)type clip:(BOOL)clip arrow:(BOOL)arrow {
    return [[self alloc] initWithType:type clip:clip arrow:arrow];
}

#pragma mark 初始化方法:初始化type、clip、arrow
- (instancetype)initWithType:(DDYLockViewType)type clip:(BOOL)clip arrow:(BOOL)arrow {
    if (self = [super init]) {
        [self lockViewPrepare];
        self.type  = type;
        self.clip  = clip;
        self.arrow = arrow;
    }
    return self;
}

- (instancetype)init {
    if (self = [super init]) {
        [self lockViewPrepare];
    }
    return self;
}

#pragma mark UI
#pragma mark 视图准备
- (void)lockViewPrepare {
    self.frame = DDYRect(0, 0, DDYSCREENW-lockViewEdgeMargin*2, DDYSCREENW-lockViewEdgeMargin*2);
    self.center = DDYPoint(DDYSCREENW/2, DDYSCREENH*3/5);
    self.clip = YES;  // 默认裁剪
    self.arrow = YES; // 默认有箭头
    self.backgroundColor = circleBgColor;
    for (int i = 0; i < 9; i++) {
        DDYCircleView *circle = [DDYCircleView circleView];
        circle.type = DDYCircleViewTypeGesture;
        circle.arrow = self.arrow;
        [self addSubview:circle];
    }
}

#pragma mark 布局子控件
- (void)layoutSubviews {
    [super layoutSubviews];
    CGFloat itemViewWH = circleRadius * 2;
    CGFloat itemMargin = (self.ddy_w - 3*itemViewWH) / 3.f;
    // 九宫格
    [self.subviews enumerateObjectsUsingBlock:^(DDYCircleView *circle, NSUInteger idx, BOOL *stop) {
        NSUInteger row = idx % 3;
        NSUInteger col = idx / 3;
        CGFloat x = itemMargin*row + row*itemViewWH + itemMargin/2;
        CGFloat y = itemMargin*col + col*itemViewWH + itemMargin/2;
        circle.tag = idx + 1;
        circle.frame = DDYRect(x, y, itemViewWH, itemViewWH);
    }];
}

#pragma mark - touch began / touch moved / touch end
#pragma mark touch began
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    // 手势重置
    [self gestureReset];
    self.currentPoint = CGPointZero;
    UITouch *touch = [touches anyObject];
    CGPoint point = [touch locationInView:self];
    [self.subviews enumerateObjectsUsingBlock:^(DDYCircleView *circle, NSUInteger idx, BOOL *stop) {
        if (CGRectContainsPoint(circle.frame, point)) {
            circle.state = DDYCircleViewStateSelected;
            [self.selectedCircleArray addObject:circle];
        }
    }];
    // 数组中最后一个对象的处理
    [self.selectedCircleArray lastObject].state = DDYCircleViewStateLastOneSelected;
    [self setNeedsDisplay];
}

#pragma mark touch moved
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
    self.currentPoint = CGPointZero;
    UITouch *touch = [touches anyObject];
    CGPoint point = [touch locationInView:self];
    [self.subviews enumerateObjectsUsingBlock:^(DDYCircleView *circle, NSUInteger idx, BOOL *stop) {
        if (CGRectContainsPoint(circle.frame, point)) {
            if (![self.selectedCircleArray containsObject:circle]) {
                [self.selectedCircleArray addObject:circle];
                // move过程中连线(包含跳跃连线的处理)
                [self calculateAngleAndConnectJumpedCircle];
            }
        } else {
            self.currentPoint = point;
        }
    }];
    
    [self.selectedCircleArray enumerateObjectsUsingBlock:^(DDYCircleView *circle, NSUInteger idx, BOOL *stop) {
        circle.state = DDYCircleViewStateSelected;
        // 如果是登录或验证密码需要改相应状态
        if (self.type == DDYLockViewTypeSetting) {
            circle.state = DDYCircleViewStateLastOneSelected;
        }
    }];
    // 数组中最后一个对象的处理
    [self.selectedCircleArray lastObject].state = DDYCircleViewStateLastOneSelected;
    [self setNeedsDisplay];
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
    self.isCleaned = NO;
    // 拼手势密码字符串
    NSMutableString *gesture = [NSMutableString string];
    for (DDYCircleView *circle in self.selectedCircleArray) {
        [gesture appendFormat:@"%@", @(circle.tag)];
    }
    CGFloat length = [gesture length];
    if (length == 0) return;
    
    if ([self.delegate respondsToSelector:@selector(lockView:state:)]) {
        // 手势绘制结果处理
        switch (self.type) {
            case DDYLockViewTypeSetting:
            {
                if (length < lockCircleLeast) {
                    [self.delegate lockView:self state:DDYLockViewStateLess];
                    [self changeCircleInSelectedCircleArrayWithSate:DDYCircleViewStateError];
                } else if ([DDYUserDefaultsGet(lockOneKey) length] < lockCircleLeast) {
                    DDYUserDefaultsSet(gesture, lockOneKey);
                    [self.delegate lockView:self state:DDYLockViewStateFirstFinish];
                } else if ([gesture isEqual:DDYUserDefaultsGet(lockOneKey)]) {
                    DDYUserDefaultsSet(gesture, lockEndKey);
                    [self.delegate lockView:self state:DDYLockViewStateSecondFinish];
                } else {
                    [self.delegate lockView:self state:DDYLockViewStateSecondError];
                    [self changeCircleInSelectedCircleArrayWithSate:DDYCircleViewStateError];
                    DDYUserDefaultsSet(nil, lockOneKey);
                }
            }
                break;
            case DDYLockViewTypeLogin:
            {
                if ([gesture isEqual:DDYUserDefaultsGet(lockEndKey)]) {
                    [self.delegate lockView:self state:DDYLockViewStateLoginFinish];
                } else {
                    [self.delegate lockView:self state:DDYLockViewStateLoginError];
                    [self changeCircleInSelectedCircleArrayWithSate:DDYCircleViewStateError];
                }
            }
                break;
            case DDYLockViewTypeVerify:
            {
                if ([gesture isEqual:DDYUserDefaultsGet(lockEndKey)]) {
                    [self.delegate lockView:self state:DDYLockViewStateVerifyFinish];
                } else {
                    [self.delegate lockView:self state:DDYLockViewStateVerifyError];
                    [self changeCircleInSelectedCircleArrayWithSate:DDYCircleViewStateError];
                }
            }
                break;
        }
    }
    [self errorToDisplay];
}

#pragma mark - 私有操作方法
#pragma mark 手势清空重置操作
- (void)gestureReset {
    // 线程安全
    @synchronized (self) {
        if (!self.isCleaned) {
            // 手势完毕,选中的圆回归普通状态
            [self changeCircleInSelectedCircleArrayWithSate:DDYCircleViewStateNormal];
            // 清空保存选中的数组
            [self.selectedCircleArray removeAllObjects];
            // 清空方向
            [self resetAllCirclesDirection];
            // 完成后改变clean状态
            self.isCleaned = YES;
        }
    }
}

#pragma mark 清空所有子控件方向
- (void)resetAllCirclesDirection {
    [self.subviews enumerateObjectsUsingBlock:^(DDYCircleView *circle, NSUInteger idx, BOOL *stop) {
        circle.angle = 0;
    }];
}

#pragma mark 改变选中数组子控件状态
- (void)changeCircleInSelectedCircleArrayWithSate:(DDYCircleViewState)state {
    [self.selectedCircleArray enumerateObjectsUsingBlock:^(DDYCircleView *circle, NSUInteger idx, BOOL *stop) {
        circle.state = state;
        // 如果是错误状态,那就将最后一个按钮特殊处理
        if (state == DDYCircleViewStateError && idx == self.selectedCircleArray.count-1) {
            circle.state = DDYCircleViewStateLastOneError;
        }
    }];
    [self setNeedsDisplay];
}

#pragma mark 每添加一个圆计算一次方向,同时处理跳跃连线
- (void)calculateAngleAndConnectJumpedCircle {
    if (self.selectedCircleArray && self.selectedCircleArray.count>1) {
        // 最后一个对象
        DDYCircleView *last1 = [self.selectedCircleArray lastObject];
        // 倒数第二个对象
        DDYCircleView *last2 = self.selectedCircleArray[self.selectedCircleArray.count-2];
        // 计算角度(反正切)
        last2.angle = atan2(last1.center.y-last2.center.y, last1.center.x-last2.center.x) + M_PI_2;
        // 跳跃连线问题
        DDYCircleView *jumpedCircle = [self selectedCircleContainPoint:[self centerPointWithPoint1:last1.center point2:last2.center]];
        if (jumpedCircle && ![self.selectedCircleArray containsObject:jumpedCircle]) {
            // 把跳跃的圆添加到已选择圆的数组(插入到倒数第二个)
            [self.selectedCircleArray insertObject:jumpedCircle atIndex:self.selectedCircleArray.count-1];
        }
    }
}

#pragma mark 提供两个点返回他们中点
- (CGPoint)centerPointWithPoint1:(CGPoint)point1 point2:(CGPoint)point2 {
    CGFloat x1 = fmax(point1.x, point2.x);
    CGFloat x2 = fmin(point1.x, point2.x);
    CGFloat y1 = fmax(point1.y, point2.y);
    CGFloat y2 = fmin(point1.y, point2.y);
    return CGPointMake((x1+x2)/2, (y1+y2)/2);
}

#pragma mark 判断点是否被圆包含(包含返回圆否则返回nil)
- (DDYCircleView *)selectedCircleContainPoint:(CGPoint)point {
    DDYCircleView *centerCircle = nil;
    for (DDYCircleView *circle in self.subviews) {
        if (CGRectContainsPoint(circle.frame, point)) {
            centerCircle = circle;
        }
    }
    if (![self.selectedCircleArray containsObject:centerCircle]) {
        // 跳跃的点角度和已选择的倒数第二个角度一致
        centerCircle.angle = [self.selectedCircleArray[self.selectedCircleArray.count-2] angle];
    }
    return centerCircle;
}

#pragma mark 错误回显重绘
- (void)errorToDisplay {
    if ([self circleState] == DDYCircleViewStateError || [self circleState] == DDYCircleViewStateLastOneError) {
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(lockDisplayTime * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            [self gestureReset];
        });
    } else {
        [self gestureReset];
    }
}

#pragma mark 获取当前圆的状态
- (DDYCircleViewState)circleState {
    return [self.selectedCircleArray firstObject].state;
}

- (void)drawRect:(CGRect)rect {
    // 没有任何选中则return
    if (self.selectedCircleArray && self.selectedCircleArray.count) {
        UIColor *lineColor = [self circleState]==DDYCircleViewStateError ? lineErrorColor : LineNormalColor;
        
        CGContextRef ctx = UIGraphicsGetCurrentContext();
        CGContextAddRect(ctx, rect);
        // 是否裁剪
        if (self.clip) {
            [self.subviews enumerateObjectsUsingBlock:^(DDYCircleView *circle, NSUInteger idx, BOOL *stop) {
                // 确定裁剪的形状
                CGContextAddEllipseInRect(ctx, circle.frame);
            }];
        }
        CGContextEOClip(ctx);
        
        for (int i = 0; i

最后利用手势区域生成不同功能(设置手势,验证手势,登录手势)控制器

#import "DDYGestureLockVC.h"

@interface DDYGestureLockVC ()

/** 解锁九宫格 */
@property (nonatomic, strong) DDYLockView *lockView;
/** TypeSetting/TypeLogin 提示文字, TypeVerify清爽无提示 */
@property (nonatomic, strong) UILabel *tipLabel;
/** TypeSetting/TypeLogin 提示视图, TypeVerify清爽无提示 */
@property (nonatomic, strong) DDYLockInfoView *infoView;

@end

@implementation DDYGestureLockVC

- (void)viewDidLoad {
    [super viewDidLoad];
    [self setupSameUI];
    [self setupDifferentUI];
}

#pragma mark UI相同部分
- (void)setupSameUI {
    self.view.backgroundColor = lockViewBgColor;
    // 解锁九宫格
    _lockView = [DDYLockView lockViewWithType:self.lockType];
    _lockView.delegate = self;
    [self.view addSubview:_lockView];
    // 提示文字
    _tipLabel = UILabelNew.labFont(DDYFont(14)).labAlignmentCenter();
    [self.view addSubview:_tipLabel.viewSetFrame(0,0,DDYSCREENW,16).viewSetCenterY(_lockView.ddy_y-30)];
}

#pragma mark UI不同部分
- (void)setupDifferentUI {
    switch (self.lockType) {
        case DDYLockViewTypeSetting:
            [self setupViewTypeSetting];
            break;
        case DDYLockViewTypeLogin:
            [self setupViewTypeLogin];
            break;
        case DDYLockViewTypeVerify:
            [self setupViewTypeVerify];
            break;
    }
}

#pragma mark 设置模式界面
- (void)setupViewTypeSetting {
    self.navigationItem.title = lockTitleSetting;
    self.lockView.type = self.lockType;
    [self showNormalMsg:lockTipBeforeSet];
    _infoView = [DDYLockInfoView infoViewWithFrame:DDYRect(0, 0, 1.2*circleRadius, 1.2*circleRadius)];
    _infoView.center = DDYPoint(DDYSCREENW/2, _tipLabel.ddy_y - _infoView.ddy_h/2-10);
    [self.view addSubview:_infoView];
}

#pragma mark 登录模式界面
- (void)setupViewTypeLogin {
    self.navigationItem.title = lockTitleLogin;
    DDYHeader *header = [DDYHeader headerWithHeaderWH:65];
    header.center = DDYPoint(DDYSCREENW/2, DDYSCREENH/5);
    header.imgArray = @[[UIImage imageWithColor:DDY_Red size:DDYSize(65, 65)]];
    header.urlArray = @[@""];
    [self.view addSubview:header];
    // 提示请输入手势密码
    [self showNormalMsg:lockTipLoginTip];
    // 忘记手势密码?
    
    // 指纹解锁
}

#pragma mark 验证模式界面
- (void)setupViewTypeVerify {
    self.navigationItem.title = lockTitleSetting;
}

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    // 清空第一个密码【登录验证都第二个(不关心第一个),设置从第一个开始(此时第一个为空)】
    DDYUserDefaultsSet(nil, lockOneKey);
}

#pragma mark DDYLockViewDelegate and UINavigationControllerDelegate
- (void)lockView:(DDYLockView *)lockView state:(DDYLockViewState)state {
    switch (state) {
        case DDYLockViewStateLess:
            [self showWarningAndShake:lockTipConnectLess];
            break;
        case DDYLockViewStateFirstFinish:
        {
            [self showNormalMsg:lockTipDrawAgain];
            [self infoViewSelectedSameAsLockView:lockView];
        }
            break;
        case DDYLockViewStateSecondFinish:
        {
            [self showNormalMsg:lockTipSuccess];
            [self.navigationController popToRootViewControllerAnimated:YES];
        }
            break;
        case DDYLockViewStateSecondError:
        {
            [self showWarningAndShake:lockTipDrawAgainError];
            [self infoViewDeselectedAllCircle];
        }
            break;
        case DDYLockViewStateLoginFinish:
            [self dismissViewControllerAnimated:YES completion:^{ }];
            break;
        case DDYLockViewStateLoginError:
            [self showWarningAndShake:lockTipVerifyError];
            break;
        case DDYLockViewStateVerifyFinish:
            [self dismissViewControllerAnimated:YES completion:^{ }];
            break;
        case DDYLockViewStateVerifyError:
            [self showWarningAndShake:lockTipVerifyError];
            break;
    }
}

#pragma mark - tipLabel不同提示
#pragma mark 普通提示
- (void)showNormalMsg:(NSString *)msg {
    [_tipLabel setText:msg];
    [_tipLabel setTextColor:lockTipNormalColor];
}

#pragma mark 摇动警示
- (void)showWarningAndShake:(NSString *)msg {
    CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"transform.translation.x"];
    animation.values = @[@(-5),@(0),@(5),@(0),@(-5),@(0),@(5),@(0)];
    animation.duration = 0.3f;
    animation.repeatCount = 2;
    animation.removedOnCompletion = YES;
    [_tipLabel setText:msg];
    [_tipLabel setTextColor:lockTipWarningColor];
    [_tipLabel.layer addAnimation:animation forKey:@"shake"];
}

#pragma mark - infoView操作
#pragma mark 设置状态第一次设置后infoView展示相应选中
- (void)infoViewSelectedSameAsLockView:(DDYLockView *)lockView {
    for (DDYCircleView *circle in lockView.subviews) {
        if (circle.state==DDYCircleViewStateSelected || circle.state==DDYCircleViewStateLastOneSelected) {
            for (DDYCircleView *infoCircle in _infoView.subviews) {
                if (infoCircle.tag == circle.tag) {
                    infoCircle.state = DDYCircleViewStateSelected;
                }
            }
        }
    }
}

#pragma mark 让infoView按钮全部取消选中
- (void)infoViewDeselectedAllCircle {
    [_infoView.subviews enumerateObjectsUsingBlock:^(DDYCircleView *circle, NSUInteger idx, BOOL *stop) {
        circle.state = DDYCircleViewStateNormal;
    }];
}

@end

九宫格手势密码_第2张图片
MyLockView.jpg

你可能感兴趣的:(九宫格手势密码)