图案解锁---优化版

源代码:

链接:
https://pan.baidu.com/s/1RbBCULYZX3IcueN9dGBClQ 密码:gkhs

主要代码:

//
//  ViewController.m
//  密码解锁---优化
//
//  Created by 许磊 on 2019/2/23.
//  Copyright © 2019年 xulei. All rights reserved.
//

#import "ViewController.h"
#import "ChangablemageView.h"


@interface ViewController ()

//不想被外部访问的信息

/**定义一个保存九个点的可变数组*/
@property (nonatomic,strong) NSMutableArray *dotViewArray;

/**定义一个保存所有线的Tag值得可变数组*/
@property (nonatomic,strong) NSMutableArray *lineTagsArray;

/**定义一个保存所有被选中的点或线的可变数组*/
@property (nonatomic,strong) NSMutableArray *selectedViewsArray;

/**保存上一个被点亮的点的Tag值*/
@property (nonatomic,assign) NSInteger lastSelectedDotTag;

/**定义一个提示接下来的操作的文本框*/
@property (nonatomic,strong) UILabel *hintLabel;

/**记录密码*/
@property (nonatomic,strong) NSMutableString *pwdString;

/**定义一个变量存储密码*/
@property (nonatomic,strong) NSString *password;

/**定义一个变量存储第一次设置的密码*/
@property (nonatomic,strong) NSString *firstPassword;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    //初始化
    [self arrayAndStringInit];
    
    //界面布局
    [self UIInit];
    
}

#pragma mark -------creatImageViewWithFrame ---------
//创建UIImageView呈现图片
- (UIImageView *)creatImageViewWithFrame:(CGRect) frame name:(NSString *)imageName{
    
    //创建
    UIImageView *imageView = [[ UIImageView alloc] initWithFrame:frame];
    //添加图片
    imageView.image = [UIImage imageNamed:imageName];
    //不显示
    imageView.hidden = YES;
    //添加
    [self.view addSubview:imageView];
    
    return imageView;
}

#pragma mark -------arrayAndStringInit ---------
//数组初始化
- (void)arrayAndStringInit{
    
    //初始化存放点的数组
    self.dotViewArray = [NSMutableArray arrayWithCapacity:9];
    
    //初始化存放Tag值得数组
    self.lineTagsArray = [NSMutableArray array];
    
    //初始化存放被选中的点或者线
    self.selectedViewsArray = [NSMutableArray array];
    
    //初始化字符串
    self.pwdString = [NSMutableString string];
    
}

#pragma mark -------UIInit ---------
//界面布局
- (void)UIInit{
    
    //创建背景图片
    {
        UIImageView *bgView = [self creatImageViewWithFrame:self.view.bounds name:@"DotLock_Normal"];
        bgView.contentMode = UIViewContentModeScaleAspectFit;
        //不隐藏
        bgView.hidden = NO;
    }
    
    //添加操作图片
    {
        //添加九个点
        [self addDot];
        
        //添加六条横线
        [self addTransverseLine];
        
        //添加六条竖线
        [self addVerticalLine];
        
        //添加八条斜线
        [self addSlantLine];
    }
    
    //提示框布局
    {
        //创建
        self.hintLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 124, self.view.frame.size.width, 50)];
        
        //文本
        // _hintLabel.text = @"请绘制密码";
        
        //字体颜色
        _hintLabel.textColor = [UIColor blackColor];
        
        //对齐方式
        _hintLabel.textAlignment = NSTextAlignmentCenter;
        
        //添加
        [self.view addSubview:_hintLabel];
        
    }
    
    //密码操作
    {
        //获取密码
        //[[NSUserDefaults standardUserDefaults] setObject:@"" forKey:@"password"];
        self.password = [[NSUserDefaults standardUserDefaults] objectForKey:@"password"];
        
        if (_password.length == 0) {
            //设置密码
            _hintLabel.text = @"请设置解锁图案";
        } else {
            //输入密码
            _hintLabel.text = @"请绘制解锁图案";
        }
        
    }
    
}

#pragma mark -------addDot ---------
//添加九个点
- (void)addDot{
    
    int index = 1;
    
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 3; j++) {
            
            //循环创建九个点
            ChangablemageView *dotImageView =  [ChangablemageView imageViewwithNormalImageName:@"DotLock_Selected" andWrongImageName:@"DotLock_Wrong" frame:CGRectMake(31+j*98, 214+i*97, 62, 62) father:self.view];
            //dotImageView.hidden = NO;
            
            //设置Tag值
            dotImageView.tag = index;
            index++;
            
            //放到存放点的数组中
            [self.dotViewArray addObject:dotImageView];
        }
    }
    
}


#pragma mark -------addTransverseLine ---------
//添加横线
//12 23 45 56 78 89
-(void)addTransverseLine{
    
    int index = 12;
    
    for (int i = 0; i < 6; i++) {
        
        //循环创建六条横线
        ChangablemageView *transverseImageView =  [ChangablemageView imageViewwithNormalImageName:@"DotLock_Normal_Highlight1" andWrongImageName:@"DotLock_Wrong_Highlight1" frame:CGRectMake(90+i%2*97, 233+i/2*99, 38, 22) father:self.view];
        //transverseImageView.hidden = NO;
        
        //赋予Tag值
        transverseImageView.tag = index;
        
        //将Tag值添加到数组中
        [self.lineTagsArray addObject:@(index)];
        
        if ((i+1)%2 == 0 && i != 0) {
            
            index = index + 11;
            
        }
        
        index = index + 11;
        
    }
    
}

#pragma mark -------addVerticalLine ---------
//添加竖线
//14 25 36 47 58 69
-(void)addVerticalLine{
    
    int index = 14;
    
    for (int i = 0; i < 6; i++) {
        
        //循环创建六条竖线
        ChangablemageView *verticalImageView =  [ChangablemageView imageViewwithNormalImageName:@"DotLock_Normal_Highlight2" andWrongImageName:@"DotLock_Wrong_Highlight2" frame:CGRectMake(51+i%3*99, 273+i/3*98, 20, 38) father:self.view];
        //verticalImageView.hidden = NO;
        
        //赋予Tag值
        verticalImageView.tag = index;
        
        //将Tag值添加到数组中
        [self.lineTagsArray addObject:@(index)];
        
        index = index + 11;
        
    }
}

#pragma mark -------addSlantLine ---------
//添加斜线
//右斜 24 35 57 68
//左斜 15 26 48 59
-(void)addSlantLine{
    
    int indexR = 15;
    
    int indexL = 24;
    
    for (int i = 0; i < 4; i++) {
        
        //循环创建四条右斜线
        ChangablemageView *rSlantLine =  [ChangablemageView imageViewwithNormalImageName:@"DotLock_Normal_Highlight3" andWrongImageName:@"DotLock_Wrong_Highlight3" frame:CGRectMake(73+i%2*99, 255+i/2*99, 64, 64) father:self.view];
        //rSlantLine.hidden = NO;
        
        //赋予Tag值
        rSlantLine.tag = indexR;
        
        //将Tag值添加到数组中
        [self.lineTagsArray addObject:@(indexR)];
        
        indexR = indexR +11;
        
        //循环创建四条左斜线
        ChangablemageView *lSlantLine =  [ChangablemageView imageViewwithNormalImageName:@"DotLock_Normal_Highlight4" andWrongImageName:@"DotLock_Wrong_Highlight4" frame:CGRectMake(82+i%2*99, 255+i/2*99, 64, 64) father:self.view];
        //lSlantLine.hidden = NO;
        
        //赋予Tag值
        lSlantLine.tag = indexL;
        
        //将Tag值添加到数组中
        [self.lineTagsArray addObject:@(indexL)];
        
        indexL = indexL +11;
        
        if (i + 1 == 2) {
            indexL = indexL + 11;
            indexR = indexR + 11;
        }
        
    }
}

#pragma mark -------touchesBegan ---------
//开始触摸
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    
    //获取触摸点的坐标
    UITouch *touch = [touches anyObject];
    CGPoint location = [touch locationInView:self.view];
    
    //判断触摸点有没有在摸一个圆点上
    for (UIImageView *dotView in _dotViewArray) {
        
        //判断
        if (CGRectContainsPoint(dotView.frame, location)) {
            
            //点亮
            dotView.hidden = NO;
            
            //记录这个点的Tag
            _lastSelectedDotTag = dotView.tag;
            
            //保存点亮的点
            [_selectedViewsArray addObject:dotView];
            
            //保存密码 拼接字符串
            [self.pwdString appendFormat:@"%ld", (long)dotView.tag];
            
        }
    }
}

#pragma mark -------touchesMoved ---------
//滑动时
-(void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    
    //获取触摸点的坐标
    UITouch *touch = [touches anyObject];
    CGPoint location = [touch locationInView:self.view];
    
    //判断触摸点有没有在摸一个圆点上
    for (UIImageView *dotView in _dotViewArray) {
        
        //判断
        if (CGRectContainsPoint(dotView.frame, location)) {
            
            //如果这个点没有被点亮
            if (dotView.hidden == YES) {
                
                //是第一个点
                if (_lastSelectedDotTag == 0) {
                    
                    //直接点亮
                    dotView.hidden = NO;
                    
                    //记录这个点的Tag
                    _lastSelectedDotTag = dotView.tag;
                    
                    //保存点亮的点
                    [_selectedViewsArray addObject:dotView];
                    
                    //保存密码 拼接字符串
                    [self.pwdString appendFormat:@"%ld", (long)dotView.tag];
                    
                } else {//不是第一个点
                    
                    //判断上一个点和当前这个点之间有没有直接的线路
                    //获取上一个点和当前这个点的Tag组成的最小两位数
                    NSInteger lineTag = _lastSelectedDotTag > dotView.tag?dotView.tag*10+_lastSelectedDotTag:_lastSelectedDotTag*10+dotView.tag;
                    NSLog(@"%ld",(long)lineTag);
                    
                    //数组里面有这条线
                    if ([_lineTagsArray containsObject:@(lineTag)]) {
                        
                        //点亮
                        dotView.hidden = NO;
                        
                        //点亮线
                        UIImageView *lineImageView = [self.view viewWithTag:lineTag];
                        lineImageView.hidden = NO;
                        
                        //记录这个点的Tag
                        _lastSelectedDotTag = dotView.tag;
                        
                        //保存点亮的点
                        [_selectedViewsArray addObject:dotView];
                        
                        //保存密码 拼接字符串
                        [self.pwdString appendFormat:@"%ld", (long)dotView.tag];
                        
                        //保存点亮的线
                        [_selectedViewsArray addObject:lineImageView];
                        
                    }
                    
                }
                
            }
            
        }
    }
}

#pragma mark -------touchesEnded ---------
//结束触摸
-(void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    
    //设置密码
    if (_password.length == 0) {
        
        //第一次
        if (_firstPassword.length == 0) {
            
            //保存刚才输入的密码
            self.firstPassword = [NSString stringWithString:_pwdString];
            [self hideAllViews];
            
            _hintLabel.text = @"请确认密码图案";
            
        } else {//第二次
            
            //设置成功
            if ([_firstPassword isEqualToString:_pwdString]) {
                
                self.hintLabel.text = @"设置成功";
                
                //保存密码
                [[NSUserDefaults standardUserDefaults] setObject:_pwdString forKey:@"password"];
                
            } else {
                
                //不一致 重新设置
                self.hintLabel.text = @"两次图案不一致 请重新绘制";
                //换色
                [self showWrong];
                //self.firstPassword = @"";
                
            }
            
        }
        
    } else {//解锁
        
        //密码正确
        if ([self.pwdString isEqualToString:_password]) {
            
            self.hintLabel.text = @"解锁成功";
            
        } else {//密码错误
            
            
            self.hintLabel.text = @"密码错误";
            
            //换色
            [self showWrong];
            
        }
        
        
    }
    
 
    
}

-(void)showWrong{
    
    for (ChangablemageView *imgView in _selectedViewsArray) {
       
        //更换状态
        [imgView changeImageWithStatus:kImageViewStatusWrong];
        
        self.hintLabel.textColor = [UIColor redColor];
        
        //延长一段时间后
        [self performSelector:@selector(hideAllViews) withObject:nil afterDelay:1];
        
    }
    
    
}

#pragma mark -------hideAllViews ---------
//隐藏所有的视图
-(void)hideAllViews{
    
    for (ChangablemageView *imgView in _selectedViewsArray) {
        //隐藏
        imgView.hidden = YES;
        //图片换回去
        [imgView changeImageWithStatus:kImageViewStatusNormal];
    }
    
    self.hintLabel.textColor = [UIColor blackColor];
    
    if ([_hintLabel.text isEqualToString:@"密码错误"]) {
        _hintLabel.text = @"请重新输入";
    }
    
    if ([_hintLabel.text isEqualToString:@"两次图案不一致 请重新绘制"]) {
        _hintLabel.text = @"请重新绘制确认密码";
    }
    
    //清空
    [_selectedViewsArray removeAllObjects];
    _lastSelectedDotTag = 0;
    [_pwdString setString:@""];
    
    
}

@end

//
//  ChangablemageView.h
//  密码解锁---优化
//
//  Created by 许磊 on 2019/2/23.
//  Copyright © 2019年 xulei. All rights reserved.
//

#import <UIKit/UIKit.h>

//图片的状态
typedef enum {
    kImageViewStatusNormal,
    kImageViewStatusWrong
} kImageViewStatus;

@interface ChangablemageView : UIImageView

/**表示正常图片的名字*/
@property (nonatomic,strong) NSString *normalImageName;

/**表示错误图片的名字*/
@property (nonatomic,strong) NSString *wrongImageName;

//根据状态改变
- (void)changeImageWithStatus:(kImageViewStatus)status;

//类方法创建图片
+(ChangablemageView *)imageViewwithNormalImageName:(NSString *)normal andWrongImageName:(NSString *)wrong frame:(CGRect)frame father:(UIView *)fatherView;

@end

//
//  ChangablemageView.m
//  密码解锁---优化
//
//  Created by 许磊 on 2019/2/23.
//  Copyright © 2019年 xulei. All rights reserved.
//

#import "ChangablemageView.h"

@implementation ChangablemageView

-(void)changeImageWithStatus:(kImageViewStatus)status {
    
    //正确图片
    if (status == kImageViewStatusNormal) {
        self.image = [UIImage imageNamed:_normalImageName];
    } else{//错误图片
        self.image = [UIImage imageNamed:_wrongImageName];
    }
    
}

+(ChangablemageView *)imageViewwithNormalImageName:(NSString *)normal andWrongImageName:(NSString *)wrong frame:(CGRect)frame father:(UIView *)fatherView{
    
    //创建
    ChangablemageView *imgView = [[ChangablemageView alloc] initWithFrame:frame];
    
    //图片名称
    imgView.normalImageName = normal;
    imgView.wrongImageName = wrong;
    
    //图片
    imgView.image = [UIImage imageNamed:normal];
    
    //状态
    imgView.hidden = YES;
    
    //添加
    [fatherView addSubview:imgView];
    
    return imgView;
}

@end

运行结果:

运行结果

附一:界面布局

1.背景图片
2.操作图片
3.加点
4.加线

附二:逻辑

  • 1.如何记录密码
    图案->密码

  • 2.如何点量点
    用一个数组保存九个点的对象 滑动过程中 实时判断触摸点有没有在九个对象中的某一个上

  • 3.点亮线
    a.触摸点必须在一个圆点上
    b.上一个点和当前这个点得有线路
    c.当前这个点没有被点亮过
    (给每一条线添加一个Tag值,两个点的Tag值组成的最小两位数)
    (用一个数组保存所有线条的Tag值)

  • 4.路径是否可到达
    只需要判断连个点组成的两位数有没有在数组里面
    如果在数组里面 说明有这条路径
    如果不在说明没有线路 记录上一个被点亮的点

附三:步骤

1.添加线条的Tag值
2.将Tag值添加到数组里面NSNumber(或转化)
3.定义一个变量 记录 上一个被点亮的点的Tag值
4.定义一个数组用于保存所有点亮的点和线
5.记录密码---每一个圆点的Tag值拼接的字符串
6.设置密码过程
7.密码错误 显示红色 切换图片视图显示的图片,自定义一个继承于UIImageView的类

附四:个人改进点

可以重写initWithFrame,自定义图案解锁

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,874评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,102评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,676评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,911评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,937评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,935评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,860评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,660评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,113评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,363评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,506评论 1 346
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,238评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,861评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,486评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,674评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,513评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,426评论 2 352

推荐阅读更多精彩内容

  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,090评论 4 62
  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,094评论 1 32
  • 国家电网公司企业标准(Q/GDW)- 面向对象的用电信息数据交换协议 - 报批稿:20170802 前言: 排版 ...
    庭说阅读 10,951评论 6 13
  • 听同事说工资太低了,果断辞职另觅出路。又面试了一家,希望有好消息。
    镇魂女孩阅读 96评论 0 0
  • 南怀瑾说:“佛教道教我还是相信睡觉,中药西药也不如九点睡觉。” 随着年龄的增大,睡眠的重要性越来越凸显出来。这不,...
    嫣然逢春阅读 778评论 0 3