iOS--开发之手势解锁

 

本文主要介绍通过手势识别实现手势解锁功能,这个方法被广泛用于手机解锁,密码验证,快捷支付等功能实现。事例效果如下所示。

 首先,我们先分析功能的实现过程,首先我们需要先看大致的实现过程:

1.加载九宫格页面

2.实现按钮被点击及滑动过程中按钮状态的改变

3.实现滑动过程中的连线

4.绘制完毕后判定密码是否正确,

5.密码判定后实现跳转。

下面我们就来用代码实现上述五个过程。

1.加载九宫格界面

1.1九宫格内控件的分布 3*3 ,我们可以自定义view(包含3*3个按钮),添加到viewController上。

复制代码
//添加view中子控件
-(void)awakeFromNib
{
//    创建按钮
    for (int i=0; i<9; i++) {
        self.LineColor=[UIColor blueColor];
    UIButton *btn=[UIButton buttonWithType:UIButtonTypeCustom];
        btn.userInteractionEnabled=NO;
    //        设置按钮属性
    [btn setBackgroundImage:[UIImage imageNamed:@"gesture_node_normal"] forState:UIControlStateNormal];
        [btn setBackgroundImage:[UIImage imageNamed:@"gesture_node_highlighted"] forState:UIControlStateHighlighted ];
        [btn setBackgroundImage:[UIImage imageNamed:@"gesture_node_error"] forState:UIControlStateDisabled];
        [self addSubview:btn];
    }
}
//布局view子控件
-(void)layoutSubviews
{
    [super layoutSubviews];
    CGFloat width=74;
    CGFloat height=74;
    CGFloat Margin=(self.bounds.size.width-3*width)/2;
//    遍历设置9个button的frame
    [self.subviews enumerateObjectsUsingBlock:^(__kindof UIView * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
//        通过tag设置按钮的索引标识
        obj.tag=idx;
            int row=(int)idx/3;
            int col=idx%3;
        obj.frame=CGRectMake(col*(Margin + width), row*(Margin +height), width, height);
    }];
}
复制代码

 

1.2将定义好的view通过xib添加到viewController上

     首先,定义一个blockview(九宫格view)的类方法,

// 加载xib文件
+(instancetype)lockView
{
    return [[[NSBundle mainBundle]loadNibNamed:@"MYblockView" owner:nil options:nil]lastObject];
}

 

     然后加载到控制器上。

复制代码
//    设置控制器view的背景图片
    self.view.backgroundColor=[UIColor colorWithPatternImage:[UIImage imageNamed:@"bg"]];
    MYblockView *blockView=[MYblockView lockView];
    blockView.center=self.view.center;
//    将blockview添加到viewController上
    [self.view addSubview:blockView];
复制代码

 

2.实现按钮被点击及滑动过程中按钮状态的改变

2.1定义数组类型的成员属性,用来装被点击的按钮

复制代码
@property(nonatomic,strong)NSMutableArray *btnArr;
//懒加载
-(NSMutableArray *)btnArr
{
    if (_btnArr==nil) {
        _btnArr=[NSMutableArray array];
    }
    return _btnArr;
}
复制代码

2.2创建路径,绘制图形

复制代码
#pragma mark----绘制图形
-(void)drawRect:(CGRect)rect
{
    if (self.btnArr.count==0 ) {
        return;
    }
//    创建路径
    UIBezierPath *path=[UIBezierPath bezierPath];
//    遍历所有按钮进行绘制
    [self.btnArr enumerateObjectsUsingBlock:^(__kindof UIButton * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
//        第一个按钮,中心点就是起点
        if (idx==0) {
            [path moveToPoint:obj.center];
        }else
        {
            [path addLineToPoint:obj.center];
        }
    }];
    [path addLineToPoint:self.currentPoint];
//    设置路径属性
    path.lineWidth=10;
    path.lineCapStyle=kCGLineCapRound;
    path.lineJoinStyle=kCGLineJoinRound;
    [self.LineColor setStroke];
//    渲染
    [path stroke];
}

 

复制代码

 2.3开始触摸

复制代码
#pragma mark-----开始触摸
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
// 获取触摸对象
    UITouch *touch=touches.anyObject;
//    获取触摸点
    CGPoint loc=[touch locationInView:self];
//    遍历按钮,判定触摸点是否在按钮上
    [self.subviews enumerateObjectsUsingBlock:^(__kindof UIButton * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        BOOL isContains=CGRectContainsPoint(obj.frame, loc);
//        如果在按钮上,将当前按钮保存在数组中,并改变按钮状态
        if (isContains&&obj.highlighted==NO) {
            [self.btnArr addObject:obj];
            obj.highlighted=YES;
        }else
        {
            obj.highlighted=NO;
        }
    }];
}
复制代码

2.4滑动过程中,重绘

复制代码
#pragma mark----开始滑动
-(void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
//    获取触摸对象
    UITouch *touch=touches.anyObject;
//    获取触摸点
    CGPoint loc=[touch locationInView:self];
    self.currentPoint=loc;
//    遍历按钮,如果按钮在滑动路径上,就改变按钮状态
    [self.subviews enumerateObjectsUsingBlock:^(__kindof UIButton * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        BOOL isContains=CGRectContainsPoint(obj.frame, loc);
        if (isContains&&obj.highlighted==NO) {
            [self.btnArr addObject:obj];
            obj.highlighted=YES;
        }
    }];
//    重绘
    [self setNeedsDisplay];
     }
复制代码

3.实现滑动过程中的连线和4.绘制完毕后判定密码是否正确,

复制代码
#pragma mark----停止滑动结束
-(void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
//    定义最后一个按钮
    UIButton *lastBtn=[self.btnArr lastObject];
//    将最后一个按钮中心点定义为相对滑动的当前点
    self.currentPoint=lastBtn.center;
//    重绘
    [self setNeedsDisplay];
//    判定密码
    self.password=[NSMutableString string];
      [self.btnArr enumerateObjectsUsingBlock:^( UIButton *  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
          [self.password appendFormat:@"%@",@(obj.tag)];
      }];
    NSLog(@"%@",self.password);
    BOOL isOk;
    if ([self.delegate respondsToSelector:@selector(blockView:finishedWithPassword:)]) {
       isOk= [self.delegate blockView:self finishedWithPassword:self.password];
    }
    if (isOk) {
        [self.btnArr enumerateObjectsUsingBlock:^(UIButton*  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
            obj.highlighted=NO;
            
        }];
        [self.btnArr removeAllObjects];
        [self setNeedsDisplay];
        
        NSLog(@"密码正确");
    }else
    {
        NSLog(@"密码错误");
    }

}
复制代码

 

注意:我们在密码判定过程中是通过根据先前布局按钮的时候定义的按钮tag值进行字符串拼接,密码传值是通过代理实现。

复制代码
#import <UIKit/UIKit.h>
@class MYblockView;
//声明代理
@protocol MYblockViewDelegate <NSObject>
@optional
//代理方法
-(BOOL) blockView:(MYblockView *)blockView finishedWithPassword:(NSString *)password;
@end
@interface MYblockView : UIView
+(instancetype)lockView;
//设置代理成员属性
@property(nonatomic,weak)id<MYblockViewDelegate>delegate;
@end
复制代码

 

5.密码判定后实现跳转。

复制代码
else
    {
        
//        关闭用户交互
        self.userInteractionEnabled=NO;
        [self.btnArr enumerateObjectsUsingBlock:^(UIButton *  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
            self.LineColor=[UIColor redColor];
            obj.highlighted=NO;
            obj.enabled=NO;
            [self setNeedsDisplay];
            
            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
//                回复按钮状态
             [self.btnArr enumerateObjectsUsingBlock:^(UIButton * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
                 obj.enabled=YES;                
             }];
//                恢复线条的颜色
                self.LineColor=[UIColor blueColor];
                
                [self.btnArr removeAllObjects];
                
                [self setNeedsDisplay];            
            });
            }];   
        NSLog(@"密码错误");
    }
    self.userInteractionEnabled=YES;

}
复制代码

         代理判定密码并实现跳转

复制代码
-(BOOL)blockView:(MYblockView *)blockView finishedWithPassword:(NSString *)password
{
    if ([password isEqualToString:@"012"]) {
        
        UIViewController *two=[UIViewController  new];
        two.view.backgroundColor=[UIColor greenColor];
        [self.navigationController pushViewController:two animated:YES];
        return  YES;
    }
    else{
           return NO;
    }
}
复制代码

 

       最后设置控制器navigationbar属性

 [self.navigationController.navigationBar setBackgroundColor:[UIColor redColor]];
   [ self.navigationController.navigationBar setTitleTextAttributes:@{
                                                            NSForegroundColorAttributeName :[UIColor whiteColor]    
                                                                     }];

转载于:https://www.cnblogs.com/bolin-123/p/5259935.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值