├── .README.md.swp ├── Image ├── Contents.json └── gestureImage │ ├── Contents.json │ ├── gestureBackgroudImg.imageset │ ├── group_2.jpg │ ├── group_2@2x.jpg │ ├── group_2@3x.jpg │ └── Contents.json │ ├── gesture_headIcon.imageset │ ├── gesture_headIcon@2x.png │ └── Contents.json │ ├── gesture_node_normal.imageset │ ├── gesture_node_normal.png │ ├── gesture_node_normal@2x.png │ └── Contents.json │ ├── gesture_node_highlighted.imageset │ ├── gesture_node_highlighted.png │ ├── gesture_node_highlighted@2x.png │ └── Contents.json │ └── gesture_indicator_normal.imageset │ ├── gesture_indicator_normal@2x.png │ └── Contents.json ├── Source ├── Gesture Page │ ├── HMUnlockPreviewView.h │ ├── HMGesturesUnlockView.h │ ├── HMUnlockView.h │ ├── HMUnlockPreviewView.m │ ├── HMGesturesUnlockView.m │ ├── HMUnlockView.xib │ └── HMUnlockView.m ├── HMGesUnLockModule.h └── HMGesUnLockModule.m ├── WeexHMGesUnlock.podspec ├── LICENSE └── README.md /.README.md.swp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shawn-tangsc/WeexPlugin-HMGesUnlock/HEAD/.README.md.swp -------------------------------------------------------------------------------- /Image/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Image/gestureImage/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Image/gestureImage/gestureBackgroudImg.imageset/group_2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shawn-tangsc/WeexPlugin-HMGesUnlock/HEAD/Image/gestureImage/gestureBackgroudImg.imageset/group_2.jpg -------------------------------------------------------------------------------- /Image/gestureImage/gestureBackgroudImg.imageset/group_2@2x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shawn-tangsc/WeexPlugin-HMGesUnlock/HEAD/Image/gestureImage/gestureBackgroudImg.imageset/group_2@2x.jpg -------------------------------------------------------------------------------- /Image/gestureImage/gestureBackgroudImg.imageset/group_2@3x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shawn-tangsc/WeexPlugin-HMGesUnlock/HEAD/Image/gestureImage/gestureBackgroudImg.imageset/group_2@3x.jpg -------------------------------------------------------------------------------- /Image/gestureImage/gesture_headIcon.imageset/gesture_headIcon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shawn-tangsc/WeexPlugin-HMGesUnlock/HEAD/Image/gestureImage/gesture_headIcon.imageset/gesture_headIcon@2x.png -------------------------------------------------------------------------------- /Image/gestureImage/gesture_node_normal.imageset/gesture_node_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shawn-tangsc/WeexPlugin-HMGesUnlock/HEAD/Image/gestureImage/gesture_node_normal.imageset/gesture_node_normal.png -------------------------------------------------------------------------------- /Image/gestureImage/gesture_node_normal.imageset/gesture_node_normal@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shawn-tangsc/WeexPlugin-HMGesUnlock/HEAD/Image/gestureImage/gesture_node_normal.imageset/gesture_node_normal@2x.png -------------------------------------------------------------------------------- /Image/gestureImage/gesture_node_highlighted.imageset/gesture_node_highlighted.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shawn-tangsc/WeexPlugin-HMGesUnlock/HEAD/Image/gestureImage/gesture_node_highlighted.imageset/gesture_node_highlighted.png -------------------------------------------------------------------------------- /Image/gestureImage/gesture_indicator_normal.imageset/gesture_indicator_normal@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shawn-tangsc/WeexPlugin-HMGesUnlock/HEAD/Image/gestureImage/gesture_indicator_normal.imageset/gesture_indicator_normal@2x.png -------------------------------------------------------------------------------- /Image/gestureImage/gesture_node_highlighted.imageset/gesture_node_highlighted@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shawn-tangsc/WeexPlugin-HMGesUnlock/HEAD/Image/gestureImage/gesture_node_highlighted.imageset/gesture_node_highlighted@2x.png -------------------------------------------------------------------------------- /Source/Gesture Page/HMUnlockPreviewView.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dyw on 2017/2/24. 3 | // Copyright © 2017年 dyw. All rights reserved. 4 | // 5 | 6 | #import 7 | 8 | @interface HMUnlockPreviewView : UIView 9 | 10 | - (void)setGesturesPassword:(NSString *)gesturesPassword; 11 | 12 | @end 13 | -------------------------------------------------------------------------------- /Source/HMGesUnLockModule.h: -------------------------------------------------------------------------------- 1 | // 2 | // HMCustomModule.h 3 | // axxtHomeApp 4 | // 5 | // Created by 唐嗣成 on 2018/5/22. 6 | // Copyright © 2018年 benmu. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "WXModuleProtocol.h" 11 | @interface HMGesUnLockModule : NSObject 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Source/Gesture Page/HMGesturesUnlockView.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dyw on 2017/2/25. 3 | // Copyright © 2017年 dyw. All rights reserved. 4 | // 5 | 6 | #import 7 | 8 | 9 | @interface HMGesturesUnlockView : UIView 10 | 11 | @property (nonatomic, copy) void(^drawRectFinishedBlock)(NSString *gesturePassword); 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Image/gestureImage/gesture_headIcon.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "gesture_headIcon@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Image/gestureImage/gesture_indicator_normal.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "gesture_indicator_normal@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Image/gestureImage/gesture_node_normal.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "gesture_node_normal.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "gesture_node_normal@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /Image/gestureImage/gesture_node_highlighted.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "gesture_node_highlighted.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "gesture_node_highlighted@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /Image/gestureImage/gestureBackgroudImg.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "group_2.jpg", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "group_2@2x.jpg", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "group_2@3x.jpg", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /WeexHMGesUnlock.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "WeexHMGesUnlock" 3 | s.version = "1.0.0" 4 | s.summary = "WeexHMGesUnlock Source ." 5 | s.homepage = 'https://github.com/shawn-tangsc/weex-plugin-ios-gesture.git' 6 | s.license = "MIT" 7 | s.authors = { "tangsicheng" => "tangscsh@icloud.com" } 8 | s.platform = :ios 9 | s.ios.deployment_target = "8.0" 10 | s.requires_arc = true 11 | s.source = { :git => 'https://github.com/shawn-tangsc/weex-plugin-ios-gesture.git', :tag => s.version.to_s } 12 | s.resources = 'Source/**/*.xib' 13 | s.source_files = "Source/*.{h,m,mm}","Source/Gesture Page/*.{h,m,mm}" 14 | 15 | end 16 | -------------------------------------------------------------------------------- /Source/Gesture Page/HMUnlockView.h: -------------------------------------------------------------------------------- 1 | // 2 | // HMUnlockView.h 3 | // WeexEros 4 | // 5 | // Created by 唐嗣成 on 2018/1/28. 6 | // Copyright © 2018年 benmu. All rights reserved. 7 | // 8 | 9 | #import 10 | typedef enum : NSUInteger { 11 | YWUnlockViewCreate,//创建手势密码 12 | YWUnlockViewUnlock//解锁手势密码 13 | } YWUnlockViewType; 14 | 15 | /** 回调 result: 操作是否成功 */ 16 | typedef void(^CallBackBlock)(BOOL result); 17 | 18 | 19 | @interface HMUnlockView : UIView 20 | 21 | /** 是否已经创建过手势密码 */ 22 | + (BOOL)haveGesturePassword; 23 | 24 | /** 获取手势密码 */ 25 | + (NSString *)getGesturesPassword; 26 | 27 | /** 删除手势密码 */ 28 | + (void)deleteGesturesPassword; 29 | 30 | /** 31 | 展示 手势密码视图 32 | @param type 类型 (YWUnlockViewCreate,//创建手势密码 YWUnlockViewUnlock//解锁手势密码) 33 | */ 34 | + (void)showUnlockViewWithType:(YWUnlockViewType)type callBack:(CallBackBlock)callBack; 35 | 36 | + (void)hideUnlockView; 37 | 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Shawn_tang 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Source/HMGesUnLockModule.m: -------------------------------------------------------------------------------- 1 | // 2 | // HMCustomModule.m 3 | // axxtHomeApp 4 | // 5 | // Created by 唐嗣成 on 2018/5/22. 6 | // Copyright © 2018年 benmu. All rights reserved. 7 | // 8 | 9 | #import "HMGesUnLockModule.h" 10 | #import 11 | #import "HMUnlockView.h" 12 | WX_PlUGIN_EXPORT_MODULE(hmGesUnlock, HMGesUnLockModule) 13 | @implementation HMGesUnLockModule 14 | @synthesize weexInstance; 15 | WX_EXPORT_METHOD(@selector(addGesturePage:)) 16 | WX_EXPORT_METHOD(@selector(checkGesturePage:)) 17 | 18 | -(void)addGesturePage:(WXModuleCallback)callback{ 19 | [HMUnlockView showUnlockViewWithType:YWUnlockViewCreate callBack:^(BOOL result) { 20 | if(callback){ 21 | if(result){ 22 | callback(@"success"); 23 | }else{ 24 | callback(@"fail"); 25 | } 26 | } 27 | }]; 28 | } 29 | 30 | -(void)checkGesturePage:(WXModuleCallback)callback{ 31 | [HMUnlockView showUnlockViewWithType:YWUnlockViewUnlock callBack:^(BOOL result) { 32 | if(callback){ 33 | if(result){ 34 | callback(@"success"); 35 | }else{ 36 | callback(@"fail"); 37 | } 38 | } 39 | }]; 40 | } 41 | 42 | 43 | @end 44 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 针对weex的简单iOS手势密码解锁插件 2 | 3 | 4 | 说明: 5 | ==================================== 6 | 本插件是针对weex做的一个手势密码解锁插件,具体的效果可以查看[基于eros的手势密码Demo](https://github.com/shawn-tangsc/eros-gesture-demo)。 7 | 8 | android端请看[andorid手势密码解锁](https://github.com/PoisonousMilkPowder/WeexPlugin-HMGesUnlock). 9 | 10 | 两种安装方式: 11 | ==================================== 12 | 13 | 第一种,通过pod本地引入 14 | ------------------------------------ 15 | 16 | 1. 首先,从git 下载到本地 17 | 18 | ``` bash 19 | ## 进入你weex项目中的ios目录,执行git clone 20 | git clone https://github.com/shawn-tangsc/WeexPlugin-HMGesUnlock 21 | 22 | ``` 23 | 24 | 2. 其次,修改你ios项目的`Podfile`文件,加入 25 | 26 | ``` bash 27 | pod 'WeexHMGesUnlock', :path=>'./WeexPlugin-HMGesUnlock/' 28 | ``` 29 | 30 | 3. 从终端进入项目`Podfile`所在的文件夹,然后执行初始化命令 31 | 32 | ``` bash 33 | pod update 34 | ``` 35 | 36 | 第二种,直接使用pod引入插件 37 | ------------------------------------ 38 | 39 | 1. 在你的`Podfile` 文件中,添加 40 | 41 | ``` 42 | pod 'WeexHMGesUnlock', :git => 'https://github.com/shawn-tangsc/WeexPlugin-HMGesUnlock.git', :tag => '1.0.0' 43 | ``` 44 | 45 | 2. 从终端进入项目`Podfile`所在的文件夹,然后执行初始化命令 46 | 47 | ``` bash 48 | pod update 49 | ``` 50 | 51 | 52 | 引入初始图片: 53 | ==================================== 54 | 1. 首先,在你的工程中,新建一个Image.xcassets 的文件夹 55 | 2. 把我git工程中,image目录下的文件拖到你创建的Image.xcassets中 56 | 3. 你可以自己按照尺寸去修改成你想要的图片,名字不要变。 57 | 58 | #### 具体步骤 59 | ![](https://ws2.sinaimg.cn/large/006tNc79gy1frmhxy97xoj31kw0we7c4.jpg) 60 | ![](https://ws3.sinaimg.cn/large/006tNc79gy1frmhyhy6nrj3134114408.jpg) 61 | ![](https://ws3.sinaimg.cn/large/006tNc79gy1frmhz4qm93j310c0vita6.jpg) 62 | ![](https://ws1.sinaimg.cn/large/006tNc79gy1frmhzj7g0hj31kw0spaf6.jpg) 63 | ![](https://ws2.sinaimg.cn/large/006tNc79gy1frmhupasnkj31gs0uidhk.jpg) 64 | 65 | 66 | weex中的使用方式: 67 | ==================================== 68 | 69 | 1. 在需要使用的文件中引入该mudule 70 | 71 | ``` bash 72 | const hmGesUnlock = weex.requireModule('hmGesUnlock'); 73 | ``` 74 | 75 | 2. 添加手势密码 76 | 77 | ``` 78 | ## 在回调中会返回成功还是失败的Bool结果 79 | hmGesUnlock.addGesturePage(function (flag) { 80 | ... 81 | }); 82 | ``` 83 | 84 | 3. 验证手势密码 85 | 86 | ``` 87 | ## 在回调中会返回成功还是失败的Bool结果 88 | hmGesUnlock.checkGesturePage(function (flag) { 89 | ... 90 | }); 91 | ``` 92 | -------------------------------------------------------------------------------- /Source/Gesture Page/HMUnlockPreviewView.m: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dyw on 2017/2/24. 3 | // Copyright © 2017年 dyw. All rights reserved. 4 | // 5 | 6 | #import "HMUnlockPreviewView.h" 7 | 8 | #define BTN_H 9 9 | #define BTN_W 9 10 | 11 | @interface HMUnlockPreviewView () 12 | 13 | @property (nonatomic, strong) NSMutableArray *buttons; 14 | 15 | @end 16 | 17 | @implementation HMUnlockPreviewView 18 | 19 | - (instancetype)initWithFrame:(CGRect)frame{ 20 | self = [super initWithFrame:frame]; 21 | if (self) { 22 | [self setup]; 23 | } 24 | return self; 25 | } 26 | 27 | - (instancetype)initWithCoder:(NSCoder *)coder{ 28 | self = [super initWithCoder:coder]; 29 | if (self) { 30 | [self setup]; 31 | } 32 | return self; 33 | } 34 | 35 | - (void)layoutSubviews { 36 | [super layoutSubviews]; 37 | NSUInteger count = self.subviews.count; 38 | int cols = 3;//总列数 39 | CGFloat x = 0,y = 0;//bounds 40 | CGFloat margin = (self.bounds.size.width - cols * BTN_W) / (cols + 1);//间距 41 | CGFloat col = 0; 42 | CGFloat row = 0; 43 | for (int i = 0; i < count; i++) { 44 | col = i%cols; 45 | row = i/cols; 46 | x = margin + (BTN_W+margin)*col; 47 | y = margin + (BTN_W+margin)*row; 48 | UIButton *btn = self.subviews[i]; 49 | btn.frame = CGRectMake(x, y, BTN_W, BTN_H); 50 | } 51 | } 52 | 53 | - (void)setup{ 54 | for (int i = 0; i < 9; i++) { 55 | UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom]; 56 | btn.userInteractionEnabled = NO; 57 | [btn setImage:[UIImage imageNamed:@"gesture_indicator_normal"] forState:UIControlStateNormal]; 58 | [btn setImage:[self imageWithColor:[UIColor colorWithRed:45.0/255.0 green:205.0/255.0 blue:244.0/255.0 alpha:1]] forState:UIControlStateSelected]; 59 | [self addSubview:btn]; 60 | [self.buttons addObject:btn]; 61 | } 62 | self.backgroundColor = [UIColor clearColor]; 63 | } 64 | //绘制一张指定颜色的圆形的图片 65 | - (UIImage *)imageWithColor:(UIColor *)color 66 | { 67 | 68 | CGRect rect = CGRectMake(0.0f, 0.0f, 9.0f, 9.0f); 69 | UIGraphicsBeginImageContext(rect.size); 70 | CGContextRef context = UIGraphicsGetCurrentContext(); 71 | CGContextAddEllipseInRect(context, rect); 72 | CGContextSetFillColorWithColor(context, [color CGColor]); 73 | CGContextClip(context); 74 | CGContextFillRect(context, rect); 75 | 76 | UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); 77 | UIGraphicsEndImageContext(); 78 | return image; 79 | } 80 | 81 | 82 | 83 | - (void)setGesturesPassword:(NSString *)gesturesPassword{ 84 | for (UIButton *button in self.buttons) { 85 | button.selected = NO; 86 | } 87 | for (int i = 0; i < gesturesPassword.length; i++) { 88 | NSInteger index = [gesturesPassword substringWithRange:NSMakeRange(i, 1)].integerValue; 89 | [self.buttons[index] setSelected:YES]; 90 | } 91 | } 92 | 93 | - (NSMutableArray *)buttons { 94 | if (!_buttons) { 95 | _buttons = [NSMutableArray array]; 96 | } 97 | return _buttons ; 98 | } 99 | 100 | @end 101 | -------------------------------------------------------------------------------- /Source/Gesture Page/HMGesturesUnlockView.m: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // Created by dyw on 2017/2/25. 4 | // Copyright © 2017年 dyw. All rights reserved. 5 | // 6 | 7 | #import "HMGesturesUnlockView.h" 8 | 9 | #define cols 3 //总列数 10 | #define linColor 0xffffff //线条颜色 11 | #define linWidth 2 //线条宽度 12 | //当前屏幕宽度 13 | #define SCREEN_WIDTH [UIScreen mainScreen].bounds.size.width 14 | //当前屏幕高度 15 | #define SCREEN_HEIGHT [UIScreen mainScreen].bounds.size.height 16 | #define HMUIColorFromRGB(rgbValue) [UIColor colorWithRed:((float)((rgbValue & 0xFF0000) >> 16))/255.0 green:((float)((rgbValue & 0xFF00) >> 8))/255.0 blue:((float)(rgbValue & 0xFF))/255.0 alpha:1.0] 17 | 18 | @interface HMGesturesUnlockView () 19 | 20 | @property (nonatomic, strong) NSMutableArray *selectedBtns; 21 | @property (nonatomic, assign) CGPoint currentPoint; 22 | 23 | @end 24 | 25 | @implementation HMGesturesUnlockView 26 | 27 | - (instancetype)initWithCoder:(NSCoder *)coder{ 28 | self = [super initWithCoder:coder]; 29 | if (self) { 30 | [self setup]; 31 | } 32 | return self; 33 | } 34 | 35 | //为什么要在这个方法中布局子控件,因为只调用这个方法,就表示父控件的尺寸确定 36 | - (void)layoutSubviews { 37 | [super layoutSubviews]; 38 | NSUInteger count = self.subviews.count; 39 | CGFloat x = 0,y = 0,w = 0,h = 0; 40 | if (SCREEN_WIDTH == 320) { 41 | w = 50; 42 | h = 50; 43 | }else { 44 | w = 58; 45 | h = 58; 46 | } 47 | 48 | CGFloat margin = (self.bounds.size.width - cols * w) / (cols + 1);//间距 49 | CGFloat col = 0; 50 | CGFloat row = 0; 51 | for (int i = 0; i < count; i++) { 52 | col = i%cols; 53 | row = i/cols; 54 | x = margin + (w+margin)*col; 55 | y = margin + (w+margin)*row; 56 | if (SCREEN_HEIGHT == 480) { 57 | y = (w+margin)*row; 58 | }else { 59 | y = margin +(w+margin)*row; 60 | } 61 | UIButton *btn = self.subviews[i]; 62 | btn.frame = CGRectMake(x, y, w, h); 63 | } 64 | } 65 | 66 | //只要调用这个方法就会把之前绘制的东西清空 重新绘制 67 | - (void)drawRect:(CGRect)rect { 68 | if (self.selectedBtns.count == 0) return; 69 | // 把所有选中按钮中心点连线 70 | UIBezierPath *path = [UIBezierPath bezierPath]; 71 | NSUInteger count = self.selectedBtns.count; 72 | for (int i = 0; i < count; i++) { 73 | UIButton *btn = self.selectedBtns[i]; 74 | if (i == 0) { 75 | [path moveToPoint:btn.center]; 76 | }else { 77 | [path addLineToPoint:btn.center]; 78 | } 79 | } 80 | [path addLineToPoint:_currentPoint ]; 81 | [HMUIColorFromRGB(linColor) set]; 82 | path.lineJoinStyle = kCGLineJoinRound; 83 | path.lineWidth = linWidth; 84 | [path stroke]; 85 | } 86 | 87 | #pragma mark - private 88 | - (void)setup { 89 | self.selectedBtns = [NSMutableArray array]; 90 | UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(pan:)]; 91 | [self addGestureRecognizer:pan]; 92 | //创建9个按钮 93 | for (int i = 0; i < 9; i++) { 94 | UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom]; 95 | btn.userInteractionEnabled = NO; 96 | [btn setImage:[UIImage imageNamed:@"gesture_node_normal"] forState:UIControlStateNormal];//非选中状态的图片 97 | [btn setImage:[UIImage imageNamed:@"gesture_node_highlighted"] forState:UIControlStateSelected];//选中状态的图片 98 | btn.tag = 1000+i; 99 | [self addSubview:btn]; 100 | } 101 | self.backgroundColor = [UIColor clearColor]; 102 | } 103 | 104 | #pragma mark - action pan 105 | - (void)pan:(UIPanGestureRecognizer *)pan { 106 | _currentPoint = [pan locationInView:self]; 107 | [self setNeedsDisplay]; 108 | for (UIButton *button in self.subviews) { 109 | if (CGRectContainsPoint(button.frame, _currentPoint) && button.selected == NO) { 110 | button.selected = YES; 111 | [self.selectedBtns addObject:button]; 112 | } 113 | } 114 | [self layoutIfNeeded]; 115 | if (pan.state == UIGestureRecognizerStateEnded) { 116 | //保存输入密码 117 | NSMutableString *gesturePwd = [NSMutableString string]; 118 | for (UIButton *button in self.selectedBtns) { 119 | [gesturePwd appendFormat:@"%ld",button.tag-1000]; 120 | button.selected = NO; 121 | } 122 | [self.selectedBtns removeAllObjects]; 123 | //手势密码绘制完成后回调 124 | !self.drawRectFinishedBlock?:self.drawRectFinishedBlock(gesturePwd); 125 | } 126 | } 127 | 128 | @end 129 | -------------------------------------------------------------------------------- /Source/Gesture Page/HMUnlockView.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /Source/Gesture Page/HMUnlockView.m: -------------------------------------------------------------------------------- 1 | // 2 | // HMUnlockView.m 3 | // WeexEros 4 | // 5 | // Created by 唐嗣成 on 2018/1/28. 6 | // Copyright © 2018年 benmu. All rights reserved. 7 | // 8 | 9 | #import "HMUnlockView.h" 10 | #import "HMGesturesUnlockView.h" 11 | #import "HMUnlockPreviewView.h" 12 | #import "BMRouterModule.h" 13 | #define GesturesPassword @"GesturesPassword" 14 | #import 15 | #import 16 | //当前屏幕宽度 17 | #define SCREEN_WIDTH [UIScreen mainScreen].bounds.size.width 18 | //当前屏幕高度 19 | #define SCREEN_HEIGHT [UIScreen mainScreen].bounds.size.height 20 | #define HMUnlock_KW [UIApplication sharedApplication].keyWindow 21 | #define HMUnlock_BD [NSBundle mainBundle] 22 | #define HMUnlock_WKSELF __weak __typeof(self)weakSelf = self 23 | #define HMUIColorFromRGB(rgbValue) [UIColor colorWithRed:((float)((rgbValue & 0xFF0000) >> 16))/255.0 green:((float)((rgbValue & 0xFF00) >> 8))/255.0 blue:((float)(rgbValue & 0xFF))/255.0 alpha:1.0] 24 | @interface HMUnlockView () 25 | /** 头像 */ 26 | @property (weak, nonatomic) IBOutlet UIImageView *iconImageView; 27 | /** 绘制密码的状态label */ 28 | @property (weak, nonatomic) IBOutlet UILabel *statusLabel; 29 | /** 重新绘制按钮 */ 30 | @property (weak, nonatomic) IBOutlet UIButton *resetGesturesPasswordButton; 31 | /** 手势密码预览图 */ 32 | @property (weak, nonatomic) IBOutlet HMUnlockPreviewView *unlockPreviewView; 33 | /** 手势密码绘制视图 */ 34 | @property (weak, nonatomic) IBOutlet HMGesturesUnlockView *gesturesUnlockView; 35 | /** 当前创建的手势密码 */ 36 | @property (nonatomic, copy) NSString *curentGesturePassword; 37 | /** 当前处理密码类型 (默认是创建密码) */ 38 | @property (nonatomic, assign) YWUnlockViewType type; 39 | /** 操作结果 回调 */ 40 | @property (nonatomic, copy) CallBackBlock block; 41 | 42 | @end 43 | 44 | @implementation HMUnlockView 45 | 46 | 47 | 48 | #pragma mark - life cycle 49 | - (void)awakeFromNib{ 50 | [super awakeFromNib]; 51 | self.type = YWUnlockViewCreate;//默认是创建密码 52 | } 53 | 54 | #pragma mark - private methods 55 | /** 根据不同的类型处理 */ 56 | - (void)handleWithType:(YWUnlockViewType)type password:(NSString *)gesturePassword{ 57 | switch (type) { 58 | case YWUnlockViewCreate://创建手势密码 59 | [self createGesturesPassword:gesturePassword]; 60 | break; 61 | case YWUnlockViewUnlock://解锁手势密码 62 | [self validateGesturesPassword:gesturePassword]; 63 | break; 64 | } 65 | } 66 | 67 | //创建手势密码 68 | - (void)createGesturesPassword:(NSString *)gesturesPassword { 69 | if (self.curentGesturePassword.length == 0) { 70 | if (gesturesPassword.length <4) { 71 | self.statusLabel.text = @"至少连接四个点,请重新输入"; 72 | [self shakeAnimationForView:self.statusLabel]; 73 | return; 74 | } 75 | if (self.resetGesturesPasswordButton.hidden == YES) { 76 | self.resetGesturesPasswordButton.hidden = NO; 77 | } 78 | self.curentGesturePassword = gesturesPassword; 79 | [self.unlockPreviewView setGesturesPassword:gesturesPassword]; 80 | self.statusLabel.text = @"请再次绘制手势密码"; 81 | return; 82 | } 83 | if ([self.curentGesturePassword isEqualToString:gesturesPassword]) {//绘制成功 84 | //保存手势密码 85 | [HMUnlockView saveGesturesPassword:gesturesPassword]; 86 | !self.block?:self.block(YES); 87 | [self hide]; 88 | }else { 89 | self.statusLabel.text = @"与上一次绘制不一致,请重新绘制"; 90 | [self shakeAnimationForView:self.statusLabel]; 91 | } 92 | } 93 | 94 | //验证手势密码 95 | - (void)validateGesturesPassword:(NSString *)gesturesPassword { 96 | static NSInteger errorCount = 5; 97 | if ([gesturesPassword isEqualToString:[HMUnlockView getGesturesPassword]]) { 98 | errorCount = 5; 99 | !self.block?:self.block(YES); 100 | [self hide]; 101 | }else { 102 | if (errorCount - 1 == 0) {//你已经输错五次了! 退出登陆! 103 | UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"手势密码已失效" message:@"请重新登陆" delegate:self cancelButtonTitle:nil otherButtonTitles:@"重新登陆", nil]; 104 | [alertView show]; 105 | errorCount = 5; 106 | [HMUnlockView deleteGesturesPassword]; 107 | return; 108 | } 109 | self.statusLabel.text = [NSString stringWithFormat:@"密码错误,还可以再输入%ld次",--errorCount]; 110 | [self shakeAnimationForView:self.statusLabel]; 111 | } 112 | } 113 | 114 | //抖动动画 115 | - (void)shakeAnimationForView:(UIView *)view{ 116 | CALayer *viewLayer = view.layer; 117 | CGPoint position = viewLayer.position; 118 | CGPoint left = CGPointMake(position.x - 10, position.y); 119 | CGPoint right = CGPointMake(position.x + 10, position.y); 120 | 121 | CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"]; 122 | [animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]]; 123 | [animation setFromValue:[NSValue valueWithCGPoint:left]]; 124 | [animation setToValue:[NSValue valueWithCGPoint:right]]; 125 | [animation setAutoreverses:YES]; // 平滑结束 126 | [animation setDuration:0.08]; 127 | [animation setRepeatCount:3]; 128 | [viewLayer addAnimation:animation forKey:nil]; 129 | } 130 | 131 | #pragma mark - public methods 132 | /** 展示 手势密码视图 */ 133 | + (void)showUnlockViewWithType:(YWUnlockViewType)type callBack:(CallBackBlock)callBack{ 134 | if(type == YWUnlockViewUnlock && ![HMUnlockView getGesturesPassword].length) return; 135 | HMUnlockView *unlockView = [HMUnlock_BD loadNibNamed:@"HMUnlockView" owner:nil options:nil].lastObject; 136 | unlockView.frame = CGRectMake(0, SCREEN_HEIGHT, SCREEN_WIDTH, SCREEN_HEIGHT); 137 | [HMUnlock_KW addSubview:unlockView]; 138 | unlockView.block = [callBack copy]; 139 | unlockView.type = type; 140 | [UIView animateWithDuration:0.25 animations:^{ 141 | unlockView.frame = CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); 142 | }]; 143 | UIImage *image = [UIImage imageNamed:@"gestureBackgroudImg"]; 144 | unlockView.layer.contents = (id) image.CGImage; 145 | } 146 | 147 | + (void)hideUnlockView{ 148 | HMUnlockView *unlockView = [HMUnlock_BD loadNibNamed:@"HMUnlockView" owner:nil options:nil].lastObject; 149 | if(unlockView != nil){ 150 | [unlockView hide]; 151 | } 152 | } 153 | 154 | /** 隐藏视图 */ 155 | - (void)hide{ 156 | [UIView animateWithDuration:0.25 animations:^{ 157 | self.frame = CGRectMake(0, SCREEN_HEIGHT, SCREEN_WIDTH, SCREEN_HEIGHT); 158 | } completion:^(BOOL finished) { 159 | [self removeFromSuperview]; 160 | }]; 161 | } 162 | 163 | #pragma mark - UIAlertViewDelegate 164 | - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex { 165 | !self.block?:self.block(NO); 166 | [self hide]; 167 | } 168 | 169 | 170 | #pragma mark - event response 171 | //点击重新绘制按钮 172 | - (IBAction)resetGesturePassword:(id)sender { 173 | self.curentGesturePassword = nil; 174 | self.statusLabel.text = @"请绘制手势密码"; 175 | self.resetGesturesPasswordButton.hidden = YES; 176 | [self.unlockPreviewView setGesturesPassword:@""]; 177 | } 178 | 179 | #pragma mark - getters and setters 180 | /** 设置密码的操作类型 */ 181 | - (void)setType:(YWUnlockViewType)type{ 182 | _type = type; 183 | self.unlockPreviewView.hidden = _type != YWUnlockViewCreate; 184 | self.iconImageView.hidden = _type == YWUnlockViewCreate; 185 | HMUnlock_WKSELF; 186 | [self.gesturesUnlockView setDrawRectFinishedBlock:^(NSString *gesturePassword) { 187 | [weakSelf handleWithType:type password:gesturePassword]; 188 | }]; 189 | } 190 | 191 | #pragma mark - other methods 192 | /** 是否已经创建过手势密码 */ 193 | + (BOOL)haveGesturePassword{ 194 | return [HMUnlockView getGesturesPassword].length?YES:NO; 195 | } 196 | 197 | /** 删除手势密码 */ 198 | + (void)deleteGesturesPassword{ 199 | [[NSUserDefaults standardUserDefaults] removeObjectForKey:GesturesPassword]; 200 | [[NSUserDefaults standardUserDefaults] synchronize]; 201 | } 202 | 203 | ///** 删除手势密码 */ 204 | //+ (void)deleteGesturesPassword:(CallBackBlock)callBack{ 205 | // [self deleteGesturesPassword]; 206 | // callBack(@"success"); 207 | //} 208 | 209 | 210 | /** 保存手势密码 */ 211 | + (void)saveGesturesPassword:(NSString *)gesturesPassword { 212 | [[NSUserDefaults standardUserDefaults] setObject:gesturesPassword forKey:GesturesPassword]; 213 | [[NSUserDefaults standardUserDefaults] synchronize]; 214 | } 215 | 216 | /** 获取手势密码 */ 217 | + (NSString *)getGesturesPassword{ 218 | return [[NSUserDefaults standardUserDefaults] objectForKey:GesturesPassword]; 219 | } 220 | 221 | 222 | @end 223 | --------------------------------------------------------------------------------