zoukankan      html  css  js  c++  java
  • iOS

    1、绘制手势锁

    • 具体实现代码见 GitHub 源码 QExtension

    • QTouchLockView.h

      	@interface QTouchLockView : UIView
      	
      	/// 提示信息框
      	@property (nonatomic, strong) UILabel *alertLabel;
      	
      	/**
      	 *  创建手势锁视图控件,获取滑动手势结果
      	 *
      	 *  @param frame    手势锁视图控件的位置尺寸
      	 *  @param result   滑动手势结果,YES 成功,NO 失败
      	 *
      	 *  @return 手势锁视图控件
      	 */
      	+ (instancetype)q_touchLockViewWithFrame:(CGRect)frame
      	                              pathResult:(void (^)(BOOL isSucceed, NSString *result))result;
      	
      	@end
      
    • QTouchLockView.m

      	#import "NSString+Hash.h"
      	
      	@interface QTouchLockView ()
      	
      	/// 存放选中的按钮
      	@property (nonatomic, strong) NSMutableArray *selectedArray;
      	
      	/// 当前被选中的按钮
      	@property (nonatomic, assign) CGPoint currentPoint;
      	
      	/// 滑动手势结果
      	@property (nonatomic, copy) void (^resultBlock)(BOOL, NSString *);
      	
      	@end
      	
      	@implementation QTouchLockView
      	
      	/// 创建手势锁界面,获取滑动结果
      	+ (instancetype)q_touchLockViewWithFrame:(CGRect)frame
      	                              pathResult:(void (^)(BOOL isSucceed, NSString *result))result {
      	    
      	    QTouchLockView *touchLockView = [[self alloc] init];
      	    
      	    CGRect tmpFrame = frame;
      	    tmpFrame.size.height = frame.size.width;
      	    
      	    touchLockView.frame = tmpFrame;
      	    touchLockView.resultBlock = result;
      	    
      	    return touchLockView;
      	}
      	
      	/// 初始化界面
      	- (instancetype)initWithFrame:(CGRect)frame {
      	    
      	    if (self = [super initWithFrame:frame]) {
      	        
      	        self.backgroundColor = [UIColor whiteColor];
      	        
      	        // 添加提示信息框
      	        self.alertLabel = [[UILabel alloc] init];
      	        self.alertLabel.textAlignment = NSTextAlignmentCenter;
      	        self.alertLabel.textColor = [UIColor redColor];
      	        self.alertLabel.backgroundColor = [UIColor clearColor];
      	        self.alertLabel.numberOfLines = 1;
      	        self.alertLabel.adjustsFontSizeToFitWidth = YES;
      	        [self addSubview:self.alertLabel];
      	        
      	        // 添加按钮
      	        for (int i = 0; i < 9; i++){
      	            
      	            UIButton *btn = [[UIButton alloc] init];
      	            
      	            NSString *bundlePath = [[[NSBundle mainBundle] resourcePath]
      	                                    stringByAppendingPathComponent:@"QTouchLockView.bundle"];
      	            
      	            UIImage *normalImage = [UIImage imageWithContentsOfFile:
      	                                    [bundlePath stringByAppendingPathComponent:@"gesture_node_normal"]];
      	            UIImage *selectedImage = [UIImage imageWithContentsOfFile:
      	                                      [bundlePath stringByAppendingPathComponent:@"gesture_node_selected"]];
      	            UIImage *highlightedImage = [UIImage imageWithContentsOfFile:
      	                                         [bundlePath stringByAppendingPathComponent:@"gesture_node_highlighted"]];
      	            
      	            [btn setBackgroundImage:normalImage forState:UIControlStateNormal];
      	            [btn setBackgroundImage:selectedImage forState:UIControlStateSelected];
      	            [btn setBackgroundImage:highlightedImage forState:UIControlStateHighlighted];
      	            
      	            // 设置 tag 值,设置按钮对应的密码值
      	            btn.tag = i + 1;
      	            
      	            // 关闭按钮的交互,响应触摸事件
      	            btn.userInteractionEnabled = NO;
      	            
      	            [self addSubview:btn];
      	        }
      	    }
      	    return self;
      	}
      	
      	/// 布局控件
      	- (void)layoutSubviews {
      	    [super layoutSubviews];
      	    
      	    // 设置按钮的 frame
      	    for (int i = 0; i < self.subviews.count - 1; i++) {
      	        
      	        // 列数
      	        NSInteger cols = 3;
      	        
      	        // 设置按钮尺寸
      	        CGFloat W = self.bounds.size.width;
      	        CGFloat H = self.bounds.size.height;
      	        CGFloat btnW = W / 5;
      	        CGFloat btnH = H / 5;
      	        
      	        // 计算按钮的 x 坐标值
      	        NSUInteger col = i % cols;
      	        CGFloat btnX = col * btnW * 2;
      	        
      	        // 计算按钮的 y 坐标值
      	        NSUInteger row = i / cols;
      	        CGFloat btnY = row * btnH * 2;
      	        
      	        // 设置按钮的 frame
      	        UIButton *btn = self.subviews[i + 1];
      	        btn.frame = CGRectMake(btnX, btnY, btnW, btnH);
      	    }
      	    
      	    // 设置提示信息框的 frame
      	    self.alertLabel.frame = CGRectMake(0, -50, self.bounds.size.width, 30);
      	}
      	
      	/// 触摸开始
      	- (void)touchesBegan:(NSSet *)touches withEvent:(nullable UIEvent *)event {
      	    
      	    // 获取触摸起始点位置
      	    CGPoint startPoint = [touches.anyObject locationInView:self];
      	    
      	    // 获取其 button
      	    UIButton *button = nil;
      	    for (UIButton *btn in self.subviews) {
      	        
      	        // 设置触摸按钮的灵敏度
      	        CGRect frame = btn.frame;
      	        CGRect tmpFrame = CGRectMake(frame.origin.x + frame.size.width / 4,
      	                                     frame.origin.y + frame.size.height / 4,
      	                                     frame.size.width / 2,
      	                                     frame.size.height / 2);
      	        
      	        // 判断某点在不在其 frame 上
      	        if (CGRectContainsPoint(tmpFrame, startPoint)) {
      	            button = btn;
      	        }
      	    }
      	    
      	    // 选中此 button
      	    if (button && button.selected == NO) {
      	        button.selected = YES;
      	        [self.selectedArray addObject:button];
      	    }
      	}
      	
      	/// 触摸移动
      	- (void)touchesMoved:(NSSet *)touches withEvent:(nullable UIEvent *)event {
      	    
      	    // 获取触摸点位置
      	    CGPoint touchPoint = [touches.anyObject locationInView:self];
      	    
      	    // 获取其 button
      	    UIButton *button = nil;
      	    for (UIButton *btn in self.subviews) {
      	        
      	        // 设置触摸按钮的灵敏度
      	        CGRect frame = btn.frame;
      	        CGRect tmpFrame = CGRectMake(frame.origin.x + frame.size.width / 4,
      	                                     frame.origin.y + frame.size.height / 4,
      	                                     frame.size.width / 2,
      	                                     frame.size.height / 2);
      	        
      	        // 判断某点在不在其 frame 上
      	        if (CGRectContainsPoint(tmpFrame, touchPoint)) {
      	            button = btn;
      	        }
      	    }
      	    
      	    // 选中此 button
      	    if (button && button.selected == NO) {
      	        button.selected = YES;
      	        [self.selectedArray addObject:button];
      	    } else {
      	        self.currentPoint = touchPoint;
      	    }
      	    
      	    // 刷新视图
      	    [self setNeedsDisplay];
      	}
      	
      	/// 触摸结束
      	- (void)touchesEnded:(NSSet *)touches withEvent:(nullable UIEvent *)event {
      	    
      	    if (self.selectedArray.count < 4) {
      	        
      	        // 触摸点数过少
      	        if (self.resultBlock) {
      	            self.resultBlock(NO, @"请至少连续连接四个点");
      	        }
      	        
      	        for (UIButton *btn in self.selectedArray) {
      	            
      	            btn.highlighted = YES;
      	            btn.selected = NO;
      	        }
      	        
      	        // 延迟
      	        dispatch_after(dispatch_time(DISPATCH_TIME_NOW,
      	                                     (int64_t)(0.5 * NSEC_PER_SEC)),
      	                       dispatch_get_main_queue(), ^{
      	                           
      	                           [self clearPath];
      	                       });
      	        
      	    } else {
      	        
      	        // 触摸完成
      	        if (self.resultBlock) {
      	            
      	            // 获取触摸结果
      	            NSMutableString *path = [NSMutableString string];
      	            for (UIButton *btn in self.selectedArray) {
      	                [path appendFormat:@"%ld", btn.tag];
      	            }
      	            
      	            // 对滑动获取的密码值进行 MD5 加密
      	            NSString *md5Path = [path q_md5String];
      	            
      	            self.resultBlock(YES, md5Path);
      	        }
      	        
      	        [self clearPath];
      	    }
      	}
      	
      	/// 触摸取消
      	- (void)touchesCancelled:(NSSet *)touches withEvent:(nullable UIEvent *)event {
      	    
      	    [self touchesEnded:touches withEvent:event];
      	}
      	
      	/// 绘制贝塞尔连接线
      	- (void)drawRect:(CGRect)rect {
      	    
      	    if (self.selectedArray.count == 0) {
      	        return;
      	    }
      	    
      	    UIBezierPath *path = [UIBezierPath bezierPath];
      	    path.lineWidth = 5;
      	    path.lineJoinStyle = kCGLineCapRound;
      	    [[UIColor colorWithRed:1 green:0 blue:0 alpha:0.5] set];
      	    
      	    for (int i = 0; i < self.selectedArray.count; i++) {
      	        
      	        UIButton *btn = self.selectedArray[i];
      	        
      	        // 如果是第一个按钮,则将其曲线的起点放在其按钮上,否则则进行连线
      	        if (i == 0) {
      	            [path moveToPoint:btn.center];
      	        } else {
      	            [path addLineToPoint:btn.center];
      	        }
      	    }
      	    
      	    // 如果不满足上述条件,按钮不存在则连接到临时点
      	    [path addLineToPoint:self.currentPoint];
      	    [path stroke];
      	}
      	
      	/// 清除连接线
      	- (void)clearPath {
      	    
      	    // 取消选中按钮
      	    for (UIButton *btn in self.selectedArray) {
      	        btn.highlighted = NO;
      	        btn.selected = NO;
      	    }
      	    
      	    // 清空选中按钮
      	    [self.selectedArray removeAllObjects];
      	    
      	    // 刷新视图
      	    [self setNeedsDisplay];
      	}
      	
      	/// 懒加载
      	- (NSMutableArray *)selectedArray {
      	    if (_selectedArray == nil) {
      	        _selectedArray = [NSMutableArray array];
      	    }
      	    return _selectedArray;
      	}
      	
      	@end
      
    • ViewController.m

      	// 设置 frame
      	CGFloat margin = 50;
      	CGFloat width = self.view.bounds.size.width - margin * 2;
      	CGRect frame = CGRectMake(margin, 200, width, width);
      	    
      	// 创建手势锁视图界面,获取滑动结果
      	QTouchLockView *touchLockView = [QTouchLockView q_touchLockViewWithFrame:frame
      	                                                              pathResult:^(BOOL isSucceed, NSString * _Nonnull result) {
      	    
      	    // 处理手势触摸结果
      	    [self dealTouchResult:result isSucceed:isSucceed];
      	}];
      	    
      	[self.view addSubview:touchLockView];
      	
      	- (void)dealTouchResult:(NSString *)result isSucceed:(BOOL)isSucceed {
      	    
      	    // 处理手势触摸结果
      	    
      	    if (isSucceed) {
      	        
      	        // 判读密码是否存在
      	        NSUserDefaults *df = [NSUserDefaults standardUserDefaults];
      	        
      	        if ([df objectForKey:@"touchLock"] == nil) {
      	            
      	            // 设置手势锁
      	            
      	            [self.passWordArrM addObject:result];
      	            
      	            if (self.passWordArrM.count == 1) {
      	                self.touchLockView.alertLabel.text = @"请再设置一次";
      	            }
      	            
      	            if (self.passWordArrM.count == 2) {
      	                if ([self.passWordArrM[0] isEqualToString:self.passWordArrM[1]]) {
      	                    
      	                    // 存储密码
      	                    [df setValue:self.passWordArrM[0] forKey:@"touchLock"];
      	                    [df synchronize];
      	                    
      	                    self.touchLockView.alertLabel.text = @"手势密码设置成功";
      	                    
      	                } else {
      	                    
      	                    // 两次滑动结果不一致
      	                    [self.passWordArrM removeAllObjects];
      	                    
      	                    self.touchLockView.alertLabel.text = @"两次滑动的结果不一致,请重新设置";
      	                }
      	            }
      	            
      	        } else {
      	            
      	            // 解锁
      	            
      	            if ([result isEqualToString:[df objectForKey:@"touchLock"] ]) {
      	                self.touchLockView.alertLabel.text = @"解锁成功";
      	            } else {
      	                self.touchLockView.alertLabel.text = @"密码不正确,请重试";
      	            }
      	        }
      	        
      	    } else {
      	        
      	        // 滑动点数过少
      	        self.touchLockView.alertLabel.text = result;
      	    }
      	}
      
    • 效果

      lockView1 lockView3

  • 相关阅读:
    mysql 开发基础系列1 表查询操作
    sql server 索引阐述系列三 表的堆组织
    sql server 索引阐述系列二 索引存储结构
    sql server 索引阐述系列一索引概述
    PyCharm 安装 pip
    Python 简单分页思路
    mysql 5.7 线程阻塞处理
    Python 练习: 简单角色游戏程序
    Docker 修改存储路径
    使用普通用户执行 docker
  • 原文地址:https://www.cnblogs.com/QianChia/p/6261937.html
Copyright © 2011-2022 走看看