日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

自定义手势解锁锁控件

發布時間:2025/6/15 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 自定义手势解锁锁控件 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一、控件的使用

模仿市面上app的手勢解鎖功能,實現的小控件,將控件封裝到了一個UIView上

?

?

二、核心原理技術

?1、觸摸事件

(1)UIView的觸摸三個觸摸響應事件:開始、移動、結束

(2)CGRectContainsPoint 判斷觸摸點的位置

?

2、Quartz2D繪圖

(1)drawRect 的重繪

?

(2)UIBezierPath 貝塞爾曲線

?

3、block成功和失敗的回調

?

?

三、實現思路

1、解鎖鍵盤中的9個小圖標,會根據驗證過程而變化顏色,所以考慮用UIButton實現,因為UIButton可以根據設置不同狀態,而獲得不同的圖片。按鈕本身不需要點擊事件的實現。

?

2、觸摸過程中,實現觸摸事件的三個方法:

(1)在開始時判斷觸摸點是否在某個按鈕上,進而改變按鈕的狀態,從而實現“點亮”。

(2)建立數組,記錄每一個被“點亮”的按鈕

(3)按照按鈕的中心點繪制連線

(4)移動過程中,繼續“點亮”按鈕并記錄

(5)觸摸結束,進行邏輯判斷,是否解鎖成功,解鎖密碼用按鈕的tag拼接(整數串)。根據成功與否,更改界面上按鈕的狀態,然后再重繪

(6)進行成功或失敗的回調

?

四、源碼

?

1、.h文件

?

@interface ZQGestureUnlockView : UIView/*** 實例化解鎖鍵盤,寬高320*320,9個按鈕,背景黑** @param frame x,y可用* @param password 輸入密碼由1~9的數組組成的字符串,不可重復* @param success 解鎖成功的回調* @param fail 解鎖失敗的回調** @return 返回手勢鎖鍵盤*/ +(instancetype)unlockWithFrame:(CGRect)frame Password:(NSString *)password successBlock:(void(^)())success failBlock:(void(^)())fail;@end

?

?

2、宏定義及私有變量定義

?

//按鈕顯示列數 #define col 3//按鈕總數 #define sum 9//按鈕的寬高 #define iconWH 80//默認狀態下連線的顏色 #define ZQLineColor [UIColor colorWithRed:0.0 green:170/255.0 blue:255/255.0 alpha:0.5]@interface ZQGestureUnlockView ()//記錄選中的按鈕 @property(nonatomic,strong) NSMutableArray * clickBtnArray;//記錄連線的顏色 @property(nonatomic,strong) UIColor * lineColor;//記錄時刻的觸摸點坐標,時刻是最新的點 @property(nonatomic,assign) CGPoint currentPoint;//用戶指定的密碼 @property(nonatomic,copy) NSString * password;//成功回調的block @property(nonatomic,copy) void(^success)();//失敗回調 block @property(nonatomic,copy) void(^fail)();@end

?

3、.m文件中的方法實現

?

//初始化方法 +(instancetype)unlockWithFrame:(CGRect)frame Password:(NSString *)password successBlock:(void(^)())success failBlock:(void(^)())fail{ZQGestureUnlockView * mainView = [[self alloc]init]; mainView.frame = CGRectMake(frame.origin.x, frame.origin.y, 320, 320);mainView.password = password;mainView.success = success; mainView.fail = fail;//生成按鈕 [mainView setupButtons];return mainView; }//生成按鈕 -(void)setupButtons {//生成按鈕for (int i = 1; i<sum+1; i++) {UIButton * button = [UIButton buttonWithType:UIButtonTypeCustom]; [button setImage:[UIImage imageNamed:@"gesture_node_normal"] forState:UIControlStateNormal];[button setImage:[UIImage imageNamed:@"gesture_node_highlighted"] forState:UIControlStateHighlighted];[button setImage:[UIImage imageNamed:@"gesture_node_error"] forState:UIControlStateDisabled];//增加按鈕的tagbutton.tag = i ;//初始狀態,讓按鈕不可交互,按鈕就是顯示用的,沒有點擊事件button.userInteractionEnabled=NO; [self addSubview:button];
}
//記錄一下默認的線的顏色self.lineColor = ZQLineColor;//設置透明self.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"bg"]]; }//布局子控件 -(void)layoutSubviews {[super layoutSubviews];CGFloat margin = (self.frame.size.width - col*iconWH)/2;[self.subviews enumerateObjectsUsingBlock:^(UIButton * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {CGFloat x= idx%col *(iconWH + margin);CGFloat y= idx/col * (iconWH +margin);obj.frame=CGRectMake(x, y, iconWH, iconWH);}];}#pragma mark - 觸摸開始,記錄開始的點 -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {UITouch * touch = touches.anyObject; CGPoint startPoint = [touch locationInView:self];//遍歷所有按鈕,判斷觸摸的位置是否在button范圍內 [self.subviews enumerateObjectsUsingBlock:^(UIButton * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {BOOL isContain = CGRectContainsPoint(obj.frame, startPoint);//如果在某個按鈕范圍內,同時這個按鈕沒有被點亮if (isContain && obj.highlighted==NO) {//改變按鈕狀態為高亮obj.highlighted = YES;//將這個按鈕記錄到“選中按鈕標記數組” [self.clickBtnArray addObject:obj]; }//如果不在某個按鈕內,那么把這個按鈕設置為不高亮(不管它是否原來是高亮狀態)else{obj.highlighted=NO;} }];//保存此刻的坐標,用于繪制連線self.currentPoint = startPoint; }#pragma mark - 觸摸移動,同樣判斷按鈕的位置 -(void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {UITouch * touch = touches.anyObject;CGPoint movePoint = [touch locationInView:self];//判斷觸摸move的位置是否在button范圍內,遍歷所有按鈕[self.subviews enumerateObjectsUsingBlock:^(UIButton * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {BOOL isContain = CGRectContainsPoint(obj.frame, movePoint);//如果觸摸范圍在某個按鈕上,并且該按鈕沒有被點亮if (isContain && obj.highlighted==NO) { obj.highlighted = YES;[self.clickBtnArray addObject:obj]; } }];//保存此刻的坐標self.currentPoint = movePoint; //調用view重繪,繪制連線 [self setNeedsDisplay]; }#pragma mark - 觸摸結束,進行邏輯判斷,重繪連線,顯示判斷后的連線狀態 -(void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {//拼裝用戶手勢結束后的密碼NSMutableString * passWordString =[NSMutableString string]; [self.clickBtnArray enumerateObjectsUsingBlock:^(UIButton * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { //合成密碼[passWordString appendFormat:@"%ld",obj.tag];}];//證明密碼正確if ([passWordString isEqualToString:self.password]) {//加延遲,是為了密碼正確后給一個短暫的停頓dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{//先把按鈕取消高亮[self.clickBtnArray enumerateObjectsUsingBlock:^(UIButton * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {obj.highlighted=NO; }];//再把數組清空 [self.clickBtnArray removeAllObjects];//最后重繪 [self setNeedsDisplay];});//執行驗證成功的回調 self.success();}//密碼錯誤else{//首先關閉view交互,避免錯誤操作self.userInteractionEnabled=NO;//先把按鈕高亮去掉,設置成enabled狀態,然后把連線變紅[self.clickBtnArray enumerateObjectsUsingBlock:^(UIButton * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {obj.enabled=NO;obj.highlighted=NO;}];self.lineColor = [UIColor redColor];[self setNeedsDisplay];//延遲一下再清除dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{//先把按鈕enable[self.clickBtnArray enumerateObjectsUsingBlock:^(UIButton * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {obj.enabled=YES;}];//再把高亮按鈕數組清空 [self.clickBtnArray removeAllObjects];//重繪 [self setNeedsDisplay];//最后在開啟交互self.userInteractionEnabled=YES;//還原默認連線顏色self.lineColor=ZQLineColor;});}//將currentPoint 設置成和最后的高亮按鈕中心一樣,這樣可以在釋放觸摸后,連線不顯示多余的“尾巴”UIButton * btn = self.clickBtnArray.lastObject;self.currentPoint= btn.center;}//view的重繪 -(void)drawRect:(CGRect)rect {UIBezierPath * path = [UIBezierPath bezierPath];[self.clickBtnArray enumerateObjectsUsingBlock:^(UIButton * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {//設置起始點if (idx==0) {[path moveToPoint:obj.center];}//設置增加點else{[path addLineToPoint:obj.center];}}];//線條顏色、寬[path setLineWidth:10];UIColor * color = self.lineColor;[color setStroke];//設置連接 [path setLineJoinStyle:kCGLineJoinRound];[path setLineCapStyle:kCGLineCapRound];//再添加實時的“線頭”if (self.clickBtnArray!=nil) {[path addLineToPoint:self.currentPoint];}//繪圖 [path stroke]; }//懶加載 -(NSMutableArray *)clickBtnArray {if (!_clickBtnArray) {_clickBtnArray=[NSMutableArray array];}return _clickBtnArray; }

?

?

五、擴展

1、解鎖鍵盤的大小可以根據實際情況定義

2、觸摸手勢的繪制采用的是不可重復的點,這個可以改進

3、不限驗證次數?

4、本例用于娛樂、學習、交流

轉載于:https://www.cnblogs.com/cleven/p/5374429.html

總結

以上是生活随笔為你收集整理的自定义手势解锁锁控件的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。