iOS實(shí)現(xiàn)手勢(shì)解鎖操作
本文主要介紹通過手勢(shì)識(shí)別實(shí)現(xiàn)手勢(shì)解鎖功能,這個(gè)方法被廣泛用于手機(jī)解鎖,密碼驗(yàn)證,快捷支付等功能實(shí)現(xiàn)。事例效果如下所示。
首先,我們先分析功能的實(shí)現(xiàn)過程,首先我們需要先看大致的實(shí)現(xiàn)過程:
1.加載九宮格頁(yè)面
2.實(shí)現(xiàn)按鈕被點(diǎn)擊及滑動(dòng)過程中按鈕狀態(tài)的改變
3.實(shí)現(xiàn)滑動(dòng)過程中的連線
4.繪制完畢后判定密碼是否正確,
5.密碼判定后實(shí)現(xiàn)跳轉(zhuǎn)。
下面我們就來用代碼實(shí)現(xiàn)上述五個(gè)過程。
1.加載九宮格界面
1.1九宮格內(nèi)控件的分布 3*3 ,我們可以自定義view(包含3*3個(gè)按鈕),添加到viewController上。
//添加view中子控件 -(void)awakeFromNib { // 創(chuàng)建按鈕 for (int i=0; i<9; i++) { self.LineColor=[UIColor blueColor]; UIButton *btn=[UIButton buttonWithType:UIButtonTypeCustom]; btn.userInteractionEnabled=NO; // 設(shè)置按鈕屬性 [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; // 遍歷設(shè)置9個(gè)button的frame [self.subviews enumerateObjectsUsingBlock:^(__kindof UIView * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { // 通過tag設(shè)置按鈕的索引標(biāo)識(shí) 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上
首先,定義一個(gè)blockview(九宮格view)的類方法,
// 加載xib文件 +(instancetype)lockView { return [[[NSBundle mainBundle]loadNibNamed:@"MYblockView" owner:nil options:nil]lastObject]; }
然后加載到控制器上。
// 設(shè)置控制器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.實(shí)現(xiàn)按鈕被點(diǎn)擊及滑動(dòng)過程中按鈕狀態(tài)的改變
2.1定義數(shù)組類型的成員屬性,用來裝被點(diǎn)擊的按鈕
@property(nonatomic,strong)NSMutableArray *btnArr; //懶加載 -(NSMutableArray *)btnArr { if (_btnArr==nil) { _btnArr=[NSMutableArray array]; } return _btnArr; }
2.2創(chuàng)建路徑,繪制圖形
#pragma mark----繪制圖形 -(void)drawRect:(CGRect)rect { if (self.btnArr.count==0 ) { return; } // 創(chuàng)建路徑 UIBezierPath *path=[UIBezierPath bezierPath]; // 遍歷所有按鈕進(jìn)行繪制 [self.btnArr enumerateObjectsUsingBlock:^(__kindof UIButton * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { // 第一個(gè)按鈕,中心點(diǎn)就是起點(diǎn) if (idx==0) { [path moveToPoint:obj.center]; }else { [path addLineToPoint:obj.center]; } }]; [path addLineToPoint:self.currentPoint]; // 設(shè)置路徑屬性 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 { // 獲取觸摸對(duì)象 UITouch *touch=touches.anyObject; // 獲取觸摸點(diǎn) CGPoint loc=[touch locationInView:self]; // 遍歷按鈕,判定觸摸點(diǎn)是否在按鈕上 [self.subviews enumerateObjectsUsingBlock:^(__kindof UIButton * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { BOOL isContains=CGRectContainsPoint(obj.frame, loc); // 如果在按鈕上,將當(dāng)前按鈕保存在數(shù)組中,并改變按鈕狀態(tài) if (isContains&&obj.highlighted==NO) { [self.btnArr addObject:obj]; obj.highlighted=YES; }else { obj.highlighted=NO; } }]; }
2.4滑動(dòng)過程中,重繪
#pragma mark----開始滑動(dòng) -(void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { // 獲取觸摸對(duì)象 UITouch *touch=touches.anyObject; // 獲取觸摸點(diǎn) CGPoint loc=[touch locationInView:self]; self.currentPoint=loc; // 遍歷按鈕,如果按鈕在滑動(dòng)路徑上,就改變按鈕狀態(tài) [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.實(shí)現(xiàn)滑動(dòng)過程中的連線和4.繪制完畢后判定密碼是否正確
#pragma mark----停止滑動(dòng)結(jié)束 -(void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { // 定義最后一個(gè)按鈕 UIButton *lastBtn=[self.btnArr lastObject]; // 將最后一個(gè)按鈕中心點(diǎn)定義為相對(duì)滑動(dòng)的當(dāng)前點(diǎn) 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(@"密碼錯(cuò)誤"); } }
注意:我們?cè)诿艽a判定過程中是通過根據(jù)先前布局按鈕的時(shí)候定義的按鈕tag值進(jìn)行字符串拼接,密碼傳值是通過代理實(shí)現(xiàn)。
#import <UIKit/UIKit.h> @class MYblockView; //聲明代理 @protocol MYblockViewDelegate <NSObject> @optional //代理方法 -(BOOL) blockView:(MYblockView *)blockView finishedWithPassword:(NSString *)password; @end @interface MYblockView : UIView +(instancetype)lockView; //設(shè)置代理成員屬性 @property(nonatomic,weak)id<MYblockViewDelegate>delegate; @end
5.密碼判定后實(shí)現(xiàn)跳轉(zhuǎn)。
else { // 關(guān)閉用戶交互 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(), ^{ // 回復(fù)按鈕狀態(tài) [self.btnArr enumerateObjectsUsingBlock:^(UIButton * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { obj.enabled=YES; }]; // 恢復(fù)線條的顏色 self.LineColor=[UIColor blueColor]; [self.btnArr removeAllObjects]; [self setNeedsDisplay]; }); }]; NSLog(@"密碼錯(cuò)誤"); } self.userInteractionEnabled=YES; }
代理判定密碼并實(shí)現(xiàn)跳轉(zhuǎn)
-(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; } }
最后設(shè)置控制器navigationbar屬性
[self.navigationController.navigationBar setBackgroundColor:[UIColor redColor]]; [ self.navigationController.navigationBar setTitleTextAttributes:@{ NSForegroundColorAttributeName :[UIColor whiteColor] }];
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助。
- IOS自定義UIButton九宮格效果
- iOS實(shí)現(xiàn)九宮格自動(dòng)生成視圖
- 關(guān)于iOS自帶九宮格拼音鍵盤和Emoji表情之間的一些坑
- IOS 九宮格布局實(shí)現(xiàn)方法
- iOS仿郵箱大師的九宮格手勢(shì)密碼解鎖
- 深入解析iOS應(yīng)用開發(fā)中九宮格視圖布局的相關(guān)計(jì)算方法
- 詳解iOS應(yīng)用UI開發(fā)中的九宮格坐標(biāo)計(jì)算與字典轉(zhuǎn)換模型
- 使用Swift代碼實(shí)現(xiàn)iOS手勢(shì)解鎖、指紋解鎖實(shí)例詳解
- iOS實(shí)現(xiàn)九宮格連線手勢(shì)解鎖
相關(guān)文章
iOS實(shí)時(shí)監(jiān)控網(wǎng)絡(luò)狀態(tài)的改變
這篇文章主要為大家詳細(xì)介紹了iOS實(shí)時(shí)監(jiān)控網(wǎng)絡(luò)狀態(tài)的改變的相關(guān)資料,感興趣的小伙伴們可以參考一下2016-08-08Swift和Objective-C 混編注意事項(xiàng)
這篇文章主要介紹了Swift和Objective-C 混編注意事項(xiàng)的相關(guān)資料,需要的朋友可以參考下2016-10-10iOS設(shè)置圓角的4種方法實(shí)例(附性能評(píng)測(cè))
這篇文章主要給大家介紹了關(guān)于iOS設(shè)置圓角的4種方法,并給大家附上了性能評(píng)測(cè),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-01-01iOS中長(zhǎng)條藍(lán)色按鈕(button)實(shí)現(xiàn)代碼
本文通過實(shí)例代碼給大家介紹了iOS中長(zhǎng)條藍(lán)色按鈕(button)實(shí)現(xiàn)方法,代碼簡(jiǎn)單易懂,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友參考下吧2017-08-08IOS 屏幕適配方案實(shí)現(xiàn)縮放window的示例代碼
這篇文章主要介紹了IOS 屏幕適配方案實(shí)現(xiàn)縮放window的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-04-04