iOS手势密码开发

作者: KingTortoise | 来源:发表于2017-09-27 11:06 被阅读1391次

    前序

    最近公司APP要做改版,其中要使用手势密码锁,所以提前写了一个小Demo练练手,该Demo参考了DBGuestureLock。这里将详细阐述代码细节,希望可以帮助到需要帮助的人。

    相关界面GIF

    Gesture.gif

    代码实现

    一、创建相关类

    • GesturePasswordButton
      该类主要是表示手势密码中的圆点
    • GesturePasswordView
      该类是手势密码View
    • GesturePasswordViewController
      该类是用于使用GesturePasswordView

    二、绘制界面

    从GIF图可以看出,手势密码一共有三种状态(正常、选择、不正确),因此现在GesturePasswordView.h文件中创建一个枚举类型

    typedef NS_ENUM(NSInteger, GesturePasswordButtonState) {
        GesturePasswordButtonStateNormal = 0,
        GesturePasswordButtonStateSelected,
        GesturePasswordButtonStateIncorrect,
    };
    

    根据Button的形状,可以在GesturePasswordView.h中定义以下属性(之所以写在GesturePasswordView.h中是为了根据不同的状态改变button的样式)

    @property (nonatomic, assign)CGFloat strokeWidth; //圆弧的宽度
    @property (nonatomic, assign)CGFloat circleRadius; //半径
    @property (nonatomic, assign)CGFloat centerPointRadius; //中心圆半径
    @property (nonatomic, assign)CGFloat lineWidth; //连接线宽度
    @property (nonatomic, strong)UIColor *strokeColor; //圆弧的填充颜色
    @property (nonatomic, strong)UIColor *fillColor; //除中心圆点外 其他部分的填充色
    @property (nonatomic, strong)UIColor *centerPointColor; //中心圆点的颜色
    @property (nonatomic, strong)UIColor *lineColor; //线条填充颜色
    @property (nonatomic, assign)BOOL showCenterPoint; //是否显示中心圆
    @property (nonatomic, assign)BOOL fillCenterPoint; //是否填充中心圆
    

    在GesturePasswordView.m文件中定义以下属性,用于后面的代码编写。(GesturePasswordStatus枚举类型将会在后面写出)

    @property (nonatomic, strong) NSMutableArray *selectorAry;//存储已经选择的按钮
    @property (nonatomic, assign)CGPoint currentPoint;//当前处于哪个按钮范围内
    @property (nonatomic, assign)GesturePasswordStatus status;//当前控件器所处状态(设置、重新设置、登录)
    @property (nonatomic, assign)NSInteger inputNum;//输入的次数
    @property (nonatomic, assign)NSInteger resetInputNum;//重置密码时验证旧密码 输入的次数
    @property (nonatomic, strong)NSString *firstPassword;//表示设置密码时 第一次输入的手势密码
    

    在GesturePasswordView.m文件中写一个方法来改变button当前的属性值

    - (void)setPropertiesByState:(GesturePasswordButtonState)buttonState{
        switch (buttonState) {
            case GesturePasswordButtonStateNormal:
                self.fillCenterPoint = YES;
                self.showCenterPoint = YES;
                self.strokeWidth = 1.f;
                self.centerPointRadius = 10.f;
                self.lineWidth = 2.f;
                self.lineColor = [UIColor whiteColor];
                self.fillColor = [UIColor whiteColor];
                self.strokeColor = [UIColor whiteColor];
                self.centerPointColor = [UIColor grayColor];
                break;
            case GesturePasswordButtonStateSelected:
                self.fillCenterPoint = YES;
                self.showCenterPoint = YES;
                self.strokeWidth = 1.f;
                self.centerPointRadius = 10.f;
                self.lineWidth = 2.f;
                self.lineColor = [UIColor greenColor];
                self.fillColor = RGBA(127, 255, 212, 1);
                self.strokeColor = RGBA(127, 255, 212, 1);
                self.centerPointColor = [UIColor greenColor];
                break;
            case GesturePasswordButtonStateIncorrect:
                self.fillCenterPoint = YES;
                self.showCenterPoint = YES;
                self.strokeWidth = 1.f;
                self.centerPointRadius = 10.f;
                self.lineWidth = 2.f;
                self.lineColor = [UIColor orangeColor];
                self.fillColor = RGBA(255, 245, 238, 1);
                self.strokeColor = RGBA(255, 245, 238, 1);
                self.centerPointColor = [UIColor orangeColor];
                break;
            default:
                break;
        }
    }
    

    在GesturePasswordView.m文件中使用initWithFrame:(CGRect)frame方法绘制手势图,这里GesturePasswordView的大小以(320,320)为基准。

    - (instancetype)initWithFrame:(CGRect)frame
    {
        self = [super initWithFrame:frame];
        if (self) {
            self.selectorAry = [[NSMutableArray alloc] init];
            [self setPropertiesByState:GesturePasswordButtonStateNormal];
            NSInteger distance = 320/3;
            NSInteger size = distance/1.5;
            NSInteger margin = size/4;
            float ins = (SCREEN_WIDTH-320)/2;
            self.circleRadius = size/2;
            for (int i = 0; i < 9; i++) {
                NSInteger row = i/3;
                NSInteger col = i%3;
                GesturePasswordButton *gesturePasswordButton = [[GesturePasswordButton alloc] initWithFrame:CGRectMake(ins+col*distance+margin, row*distance+margin, size, size)];
                [gesturePasswordButton setTag:i+1];
                [self addSubview:gesturePasswordButton];
            }
            [self setBackgroundColor:[UIColor clearColor]];
        }
        return self;
    }
    

    在GesturePasswordButton.m文件中重新initWithFrame:(CGRect)frame方法。

    - (instancetype)initWithFrame:(CGRect)frame
    {
        self = [super initWithFrame:frame];
        if (self) {
            self.userInteractionEnabled = NO;
        }
        return self;
    }
    

    在GesturePasswordButton.m文件中重新- (void)drawRect:(CGRect)rect方法。

    • 获取到父视图(GesturePasswordView),使用其相关描述button的属性。
        __weak GesturePasswordView *gesView = nil;
        if ([self.superview isKindOfClass:[GesturePasswordView class]]) {
            gesView = (GesturePasswordView *)self.superview;
        }
    
    • 绘制外圈大圆
        CGFloat radius = gesView.circleRadius - gesView.strokeWidth;
        CGContextRef context = UIGraphicsGetCurrentContext();
        CGContextSetLineWidth(context, gesView.strokeWidth);
        CGPoint centerPoint = CGPointMake(rect.size.width/2, rect.size.height/2);
        CGFloat startAngle = -((CGFloat)M_PI/2);
        CGFloat endAngle = ((2 * (CGFloat)M_PI) + startAngle);
        [gesView.strokeColor setStroke];
        CGContextAddArc(context, centerPoint.x, centerPoint.y, radius+gesView.strokeWidth/2, startAngle, endAngle, 0);
        CGContextStrokePath(context);//CGContextStrokePath来描线,即形状 
    
    • 根据是否显示中心点绘制形状
    if (gesView.showCenterPoint) {
            [gesView.fillColor set];//同时设置填充和边框色
            CGContextAddArc(context, centerPoint.x, centerPoint.y, radius, startAngle, endAngle, 0);
            CGContextFillPath(context);//CGContextFillPath来填充形状内的颜色
            if (gesView.fillCenterPoint) {
                [gesView.centerPointColor set];//同时设置填充和边框色
            }else{
                [gesView.centerPointColor setStroke];//设置边框色
            }
            CGContextAddArc(context, centerPoint.x, centerPoint.y, gesView.centerPointRadius, startAngle, endAngle, 0);
            if (gesView.fillCenterPoint) {
                CGContextFillPath(context);//CGContextFillPath来填充形状内的颜色
            }else{
                CGContextStrokePath(context);//CGContextStrokePath来描线,即形状 
            }
        }
    

    整体drawRect方法如下:

    - (void)drawRect:(CGRect)rect
    {
        [super drawRect:rect];
        __weak GesturePasswordView *gesView = nil;
        if ([self.superview isKindOfClass:[GesturePasswordView class]]) {
            gesView = (GesturePasswordView *)self.superview;
        }
        CGFloat width = rect.size.height > rect.size.width ? rect.size.width : rect.size.height;
        CGFloat radius = (width - 2*gesView.strokeWidth)/2;
        if (radius > (gesView.circleRadius - gesView.strokeWidth)) {
            radius = gesView.circleRadius - gesView.strokeWidth;
        }
        CGContextRef context = UIGraphicsGetCurrentContext();
        CGContextSetLineWidth(context, gesView.strokeWidth);
        CGPoint centerPoint = CGPointMake(rect.size.width/2, rect.size.height/2);
        CGFloat startAngle = -((CGFloat)M_PI/2);
        CGFloat endAngle = ((2 * (CGFloat)M_PI) + startAngle);
        [gesView.strokeColor setStroke];
        CGContextAddArc(context, centerPoint.x, centerPoint.y, radius+gesView.strokeWidth/2, startAngle, endAngle, 0);
        CGContextStrokePath(context);//CGContextStrokePath来描线,即形状 
        
        if (gesView.showCenterPoint) {
            [gesView.fillColor set];//同时设置填充和边框色
            CGContextAddArc(context, centerPoint.x, centerPoint.y, radius, startAngle, endAngle, 0);
            CGContextFillPath(context);//CGContextFillPath来填充形状内的颜色
            
            if (gesView.fillCenterPoint) {
                [gesView.centerPointColor set];//同时设置填充和边框色
            }else{
                [gesView.centerPointColor setStroke];//设置边框色
            }
            
            CGContextAddArc(context, centerPoint.x, centerPoint.y, gesView.centerPointRadius, startAngle, endAngle, 0);
            if (gesView.fillCenterPoint) {
                CGContextFillPath(context);//CGContextFillPath来填充形状内的颜色
            }else{
                CGContextStrokePath(context);//CGContextStrokePath来描线,即形状 
            }
        }
    }
    

    这样的话只需要在GesturePasswordViewController中加载GesturePasswordView就可以显示出手势密码的界面。

    三、实现三种手势状态

    为了实现手势的三种状态,我们需要获取到用户的触摸动作,这里我们将使用UIResponder类,UIResponder类是专门用来响应用户的操作处理各种事件的,所以我们需要在GesturePasswordView.m实现touchesBegan、touchesMoved、touchesEnded方法。

    • touchesBegan方法
    - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
    {
        [super touchesBegan:touches withEvent:event];
        UITouch *touch = [touches anyObject];
        CGPoint point = [touch locationInView:self];//获取触摸点在view中的位置
        self.currentPoint = point;
        for (GesturePasswordButton *btn in self.subviews) {
            if (CGRectContainsPoint(btn.frame, point)) {//判断触摸点是否在当前btn的范围之内
                [btn setSelected:YES];
                if (![self.selectorAry containsObject:btn]) {
                    [self.selectorAry addObject:btn];
                    [self setPropertiesByState:GesturePasswordButtonStateSelected];//改变该btn的状态
                }
            }
        }
        [self setNeedsDisplay];//重绘view来画线
    }
    
    • touchesMoved方法
    - (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
    {
        [super touchesMoved:touches withEvent:event];
        UITouch *touch = [touches anyObject];
        CGPoint point = [touch locationInView:self];
        self.currentPoint = point;
        for (GesturePasswordButton *btn in self.subviews) {
            if (CGRectContainsPoint(btn.frame, point)) {
                [btn setSelected:YES];
                if (![self.selectorAry containsObject:btn]) {
                    [self.selectorAry addObject:btn];
                    [self setPropertiesByState:GesturePasswordButtonStateSelected];
                }
            }
        }
        [self setNeedsDisplay];
    }
    
    • touchesEnded方法
    - (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
    {
        [super touchesEnded:touches withEvent:event];
        GesturePasswordButton *btn = [self.selectorAry lastObject];
        [self setCurrentPoint:btn.center];
        [self setNeedsDisplay];
    }
    
    • 调用drawRect方法 重绘view
    - (void)drawRect:(CGRect)rect{
        [super drawRect:rect];
        if ([self.selectorAry count] == 0) {
            return;
        }
        UIBezierPath *path = [UIBezierPath bezierPath];
        [path setLineWidth:self.lineWidth];
        [self.lineColor set];
        [path setLineJoinStyle:kCGLineJoinRound];
        [path setLineCapStyle:kCGLineCapRound];
        for (NSInteger i = 0; i < self.selectorAry.count; i ++) {
            GesturePasswordButton *btn = self.selectorAry[i];
            if (i == 0) {
                [path moveToPoint:[btn center]];
            }else{
                [path addLineToPoint:[btn center]];
            }
            [btn setNeedsDisplay];
        }
        [path addLineToPoint:self.currentPoint];
        [path stroke];
    }
    
    • 为了实现当用户输入错误后,不正确状态显示0.5秒后恢复为正常状态,需要在上面实现的setPropertiesByState方法中加入如下代码,另外实现resetButtons和lockState方法
    case GesturePasswordButtonStateNormal:
                [self setUserInteractionEnabled:YES];\\设置当前用户可以进行触摸操作
                [self resetButtons];
                self.fillCenterPoint = YES;
    
    case GesturePasswordButtonStateIncorrect:
                [self setUserInteractionEnabled:NO];\\设置当前用户不可进行触摸操作
                self.fillCenterPoint = YES;
                self.showCenterPoint = YES;
                self.strokeWidth = 1.f;
                self.centerPointRadius = 10.f;
                self.lineWidth = 2.f;
                self.lineColor = [UIColor orangeColor];
                self.fillColor = RGBA(255, 245, 238, 1);
                self.strokeColor = RGBA(255, 245, 238, 1);
                self.centerPointColor = [UIColor orangeColor];
                [self performSelector:@selector(lockState:) withObject:[NSArray arrayWithObject:[NSNumber numberWithInteger:GesturePasswordButtonStateNormal]] afterDelay:0.5f];\\0.5秒后执行lockState方法
    
    \\重置selectorAry数组
    - (void)resetButtons {
        for (NSInteger i=0; i<[self.selectorAry count]; i++) {
            GesturePasswordButton *button = self.selectorAry[i];
            [button setSelected:NO];
        }
        [self.selectorAry removeAllObjects];
        [self setNeedsDisplay];
    }
    
    \\切换btn状态
    - (void)lockState:(NSArray *)states {
        NSNumber *stateNumber = [states objectAtIndex:0];
        [self setPropertiesByState:[stateNumber integerValue]];
    }
    

    四、调用GesturePasswordView

    现在我们要明确一下这个GesturePasswordView主要用于手势登录、设置手势密码、重置手势密码这三种情况。那么在GesturePasswordViewController.h中可以创建一个枚举类型。

    typedef NS_ENUM(NSInteger, GesturePasswordStatus) {
        GesturePasswordStatusSet           = 0,\\设置
        GesturePasswordStatusReset         = 1,\\重置
        GesturePasswordStatusLogin         = 2,\\登录
    };
    

    登录、设置、重置三种状态下的流程图

    流程图.png

    根据流程图我们可以在GesturePasswordView.h中创建六种类型的Block方法

    @property (nonatomic, copy) void(^verificationPassword)();//验证旧密码正确
    @property (nonatomic, copy) void(^verificationError)();//验证旧密码错误
    @property (nonatomic, copy) void(^onPasswordSet)();//第一次输入密码
    @property (nonatomic, copy) void(^onGetCorrectPswd)();//第二次输入密码且和第一次一样
    @property (nonatomic, copy) void(^onGetIncorrectPswd)();//第二次输入密码且和第一次不一样
    @property (nonatomic, copy) void(^errorInput)();//手势密码小于四位数
    

    根据三种状态我们可以在GesturePasswordView.h中创建三种初始化方法

    +(instancetype)status:(GesturePasswordStatus)status frame:(CGRect)frame onGetCorrectPswd:(void (^)())GetCorrectPswd onGetIncorrectPswd:(void (^)())GetIncorrectPswd errorInput:(void (^)())errorInput;//用于登录
    
    +(instancetype)status:(GesturePasswordStatus)status frame:(CGRect)frame  onPasswordSet:(void (^)())onPasswordSet onGetCorrectPswd:(void (^)())GetCorrectPswd onGetIncorrectPswd:(void (^)())GetIncorrectPswd errorInput:(void (^)())errorInput;//用于设置
    
    +(instancetype)status:(GesturePasswordStatus)status frame:(CGRect)frame verificationPassword:(void (^)())verificationPassword verificationError:(void (^)())verificationError onPasswordSet:(void (^)())onPasswordSet onGetCorrectPswd:(void (^)())GetCorrectPswd onGetIncorrectPswd:(void (^)())GetIncorrectPswd errorInput:(void (^)())errorInput;//用于重置
    

    在GesturePasswordView.m中实现这三种方法

    +(instancetype)status:(GesturePasswordStatus)status frame:(CGRect)frame onGetCorrectPswd:(void (^)())GetCorrectPswd onGetIncorrectPswd:(void (^)())GetIncorrectPswd errorInput:(void (^)())errorInput
    {
        return [self status:status frame:frame onPasswordSet:nil onGetCorrectPswd:GetCorrectPswd onGetIncorrectPswd:GetIncorrectPswd errorInput:errorInput];
    }
    
    +(instancetype)status:(GesturePasswordStatus)status frame:(CGRect)frame  onPasswordSet:(void (^)())onPasswordSet onGetCorrectPswd:(void (^)())GetCorrectPswd onGetIncorrectPswd:(void (^)())GetIncorrectPswd errorInput:(void (^)())errorInput
    {
        return [self status:status frame:frame verificationPassword:nil verificationError:nil onPasswordSet:onPasswordSet onGetCorrectPswd:GetCorrectPswd onGetIncorrectPswd:GetIncorrectPswd errorInput:errorInput];
    }
    
    +(instancetype)status:(GesturePasswordStatus)status frame:(CGRect)frame verificationPassword:(void (^)())verificationPassword verificationError:(void (^)())verificationError onPasswordSet:(void (^)())onPasswordSet onGetCorrectPswd:(void (^)())GetCorrectPswd onGetIncorrectPswd:(void (^)())GetIncorrectPswd errorInput:(void (^)())errorInput
    {
        GesturePasswordView *gesView = [[GesturePasswordView alloc] initWithFrame:frame];
        gesView.status = status;
        gesView.verificationPassword = verificationPassword;
        gesView.verificationError = verificationError;
        gesView.onPasswordSet = onPasswordSet;
        gesView.onGetCorrectPswd = GetCorrectPswd;
        gesView.onGetIncorrectPswd = GetIncorrectPswd;
        gesView.errorInput = errorInput;
        return gesView;
    }
    

    在touchesEnded方法中,我们可以根据当前出入哪种状态做出相应的处理,所以touchesEnded方法应该是这样的:

    - (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
    {
        [super touchesEnded:touches withEvent:event];
        if (self.selectorAry.count < 4) {
            self.errorInput();
            [self setPropertiesByState:GesturePasswordButtonStateNormal];
        }else if (self.status == GesturePasswordStatusSet) {
            [self setPasswordBlock];
        }else if(self.status == GesturePasswordStatusReset){
            NSString *password = [self getPassword];
            NSString *inputPassword  = [[NSString alloc] init];
            if (self.resetInputNum == 0) {
                for (GesturePasswordButton *btn in self.selectorAry) {
                    inputPassword = [inputPassword stringByAppendingFormat:@"%@",@(btn.tag)];
                }
                if ([inputPassword isEqualToString:password]) {
                    self.verificationPassword();
                    self.resetInputNum += 1;
                    [self performSelector:@selector(lockState:) withObject:[NSArray arrayWithObject:[NSNumber numberWithInteger:GesturePasswordButtonStateNormal]] afterDelay:0.3f];
                }else{
                    self.verificationError();
                    [self setPropertiesByState:GesturePasswordButtonStateIncorrect];
                }
            }else if(self.resetInputNum == 1){
                [self setPasswordBlock];
            }
        }else if(self.status == GesturePasswordStatusLogin){
            NSString *password = [self getPassword];
            NSString *inputPassword  = [[NSString alloc] init];
            for (GesturePasswordButton *btn in self.selectorAry) {
                inputPassword = [inputPassword stringByAppendingFormat:@"%@",@(btn.tag)];
            }
            if ([inputPassword isEqualToString:password]) {
                self.onGetCorrectPswd();
                [self setPropertiesByState:GesturePasswordButtonStateNormal];
            }else{
                self.onGetIncorrectPswd();
                [self setPropertiesByState:GesturePasswordButtonStateIncorrect];
            }
        }
        GesturePasswordButton *btn = [self.selectorAry lastObject];
        [self setCurrentPoint:btn.center];
        [self setNeedsDisplay];
    }
    
    - (void)setPasswordBlock
    {
        if (self.inputNum == 0) {
            self.firstPassword = [[NSString alloc] init];
            for (GesturePasswordButton *btn in self.selectorAry) {
                self.firstPassword = [self.firstPassword stringByAppendingFormat:@"%@",@(btn.tag)];
            }
            self.onPasswordSet();
            self.inputNum += 1;
            [self performSelector:@selector(lockState:) withObject:[NSArray arrayWithObject:[NSNumber numberWithInteger:GesturePasswordButtonStateNormal]] afterDelay:0.3f];
        }else{
            NSString *secondPassword = [[NSString alloc] init];
            for (GesturePasswordButton *btn in self.selectorAry) {
                secondPassword = [secondPassword stringByAppendingFormat:@"%@",@(btn.tag)];
            }
            if ([self.firstPassword isEqualToString:secondPassword]) {
                [self savePassWord:secondPassword];
                self.onGetCorrectPswd();
                [self performSelector:@selector(lockState:) withObject:[NSArray arrayWithObject:[NSNumber numberWithInteger:GesturePasswordButtonStateNormal]] afterDelay:0.3f];
            }else{
                self.onGetIncorrectPswd();
                [self setPropertiesByState:GesturePasswordButtonStateIncorrect];
                self.inputNum -= 1;
            }
        }
    }
    

    存取密码的方法

    - (void)savePassWord:(NSString *)password
    {
        NSUserDefaults *userdefault = [NSUserDefaults standardUserDefaults];
        [userdefault setObject:@{@"password":password} forKey:GESTUREPASSWORD];
        [userdefault synchronize];
    }
    
    - (NSString *)getPassword
    {
        NSDictionary *dic = [[NSUserDefaults standardUserDefaults] objectForKey:GESTUREPASSWORD];
        return [dic objectForKey:@"password"];
    }
    

    在GesturePasswordViewController.h这样调用

    if (self.status == GesturePasswordStatusSet) {
            self.infoLabel.text = @"请设置手势密码";
            GesturePasswordView *view = [GesturePasswordView status:GesturePasswordStatusSet frame:CGRectMake(0, 200,  SCREEN_WIDTH, 400) onPasswordSet:^() {
                self.infoLabel.text = @"请重新输入刚才设置的手势密码";
            } onGetCorrectPswd:^ {
                self.infoLabel.text = @"设置成功";
                [weakSelf setGesturePasswordSwitchOpen];
            } onGetIncorrectPswd:^ {
                self.infoLabel.text = @"与上一次输入不一致,请重新设置";
            } errorInput:^{
                self.infoLabel.text = @"请至少连接4个点";
            }];
            [self.view addSubview:view];
        }else if (self.status == GesturePasswordStatusReset){
            self.infoLabel.text = @"请验证旧密码";
            GesturePasswordView *view = [GesturePasswordView status:GesturePasswordStatusReset frame:CGRectMake(0, 200,  SCREEN_WIDTH, 400) verificationPassword:^{
                self.infoLabel.text = @"请输入新的手势密码";
            } verificationError:^{
                self.infoLabel.text = @"旧密码验证错误";
            }  onPasswordSet:^ {
                self.infoLabel.text = @"请重新输入刚才设置的手势密码";
            } onGetCorrectPswd:^ {
                self.infoLabel.text = @"设置成功";
                [weakSelf setGesturePasswordSwitchOpen];
            } onGetIncorrectPswd:^ {
                self.infoLabel.text = @"与上一次输入不一致,请重新设置";
            } errorInput:^{
                self.infoLabel.text = @"请至少连接4个点";
            }];
            [self.view addSubview:view];
        }else if (self.status == GesturePasswordStatusLogin){
            self.infoLabel.text = @"请输入手势密码";
            GesturePasswordView *view = [GesturePasswordView status:GesturePasswordStatusLogin frame:CGRectMake(0, 200,  SCREEN_WIDTH, 400) onGetCorrectPswd:^ {
                self.infoLabel.text = @"解锁成功";
                [self loginSuccess];
            } onGetIncorrectPswd:^ {
                self.infoLabel.text = @"密码错误,请重新输入";
            } errorInput:^{
                self.infoLabel.text = @"请至少连接4个点";
            }];
            [self.view addSubview:view];
        }
    

    结束语

    整个思路大致就是这样的,主体实现的代码已经在文章中写出来了,当然还有手势密码锁的开启与关闭等一些细节代码没有写出,如果需要完整代码的可以前往github下载Demo。如果有什么不对的地方,希望大家可以及时的指出,谢谢!!!

    相关文章

      网友评论

        本文标题:iOS手势密码开发

        本文链接:https://www.haomeiwen.com/subject/msgsextx.html