zoukankan      html  css  js  c++  java
  • UI进阶--Quartz2D和触摸事件的简单使用:手势解锁

    需求:实现一个简易的手势解锁应用,具体效果如下图所示:

    实现步骤:

    1、代码创建界面,自定义一个view,设置view的背景,颜色等属性;

    2在自定义的view中,定义2个属性,一个是存储被选中按钮的可变数组,另外一个是最后的触摸点(CGPoint);

    3、重写initWithFrame方法,在这里,自定义一个方法给initWithFrame方法调用即可,这个自定义的方法里,初始化9个按钮,设置每个按钮的tag,正常状态下的图片以及选中状态的图片,并设置和用户的交互为NO

    4在自定义的view中的layoutSubviews方法中,自定义9个按钮;

    5、在touchesBegan:touchesMoved:方法中,判断触摸点是否在view上的9个按钮中,如果在,那么设置按钮的选中状态;(在这里,只写其中一个方法即可,另外一个方法直接调用)

    5.1、进行遍历,并把选中的按钮放在选中按钮的可变数组中,并记录最后的触摸点;

    5.2、在最后记得重绘图形,调用setNeedsDisplay方法;

    6、在drawRect:方法中,绘制选中按钮之间的连线;

    6.1、遍历选中按钮数组,得到选中按钮的数量,如果为0,直接返回;

    6.2、使用UIBezierPath画线;

    6.3、对绘制的线进行线宽,颜色、样式等设置

    6.4、对绘制的线进行渲染;

    7、在touchesEnded:方法中取消连线,并移除选中的按钮,最后重绘图形;

    8、选择完密码后,把密码传回给控制器,让控制器判断选择是否正确;

    8.1、在自定义的view中设置代理;

    8.2、在touchesEnded:方法中拼接选中按钮的索引;

    8.3、通知代理按钮的选择;

    具体实现代码:

     

    Controller:

     1 //
     2 //  ViewController.m
     3 //  1-4-Deblocking
     4 //
     5 //  Created by xiaomoge on 15/1/4.
     6 //  Copyright (c) 2015年 xiaomoge. All rights reserved.
     7 //
     8 
     9 #import "ViewController.h"
    10 #import "DeblockingView.h"
    11 @interface ViewController () <DeblockingViewDelegate>
    12 
    13 @end
    14 
    15 @implementation ViewController
    16 
    17 - (void)viewDidLoad {
    18     [super viewDidLoad];
    19     //设置背景颜色
    20     self.view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"Home_refresh_bg"]];
    21     //取得当前屏幕的宽度
    22     CGFloat screenW = [UIScreen mainScreen].bounds.size.width;
    23     //初始化一个DeblockingView
    24     DeblockingView *deblockingView = [[DeblockingView alloc] initWithFrame:CGRectMake(0, 0, screenW, screenW)];
    25     //设置背景颜色
    26     deblockingView.backgroundColor = [UIColor clearColor];
    27    //居中显示
    28     deblockingView.center = self.view.center;
    29    //设置代理
    30     deblockingView.delegate = self;
    31     [self.view addSubview:deblockingView];
    32 }
    33 #pragma mark - DeblockingViewDelegate方法
    34 - (void)selectBtn:(DeblockingView *)deblockingView andSelectPwd:(NSString *)pwd {
    35     NSString *tips;
    36     if ([pwd isEqualToString:@"03478"]) {//设置一个固定的密码
    37         tips = @"解锁成功";
    38     }else {
    39         tips = @"密码错误";
    40     }
    41     //弹出窗口提示
    42     UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"提示" message:tips delegate:nil cancelButtonTitle:nil otherButtonTitles:@"确定", nil];
    43     [alert show];
    44 }
    45 @end

    View:

     1 //
     2 //  DeblockingView.h
     3 //  1-4-Deblocking
     4 //
     5 //  Created by xiaomoge on 15/1/4.
     6 //  Copyright (c) 2015年 xiaomoge. All rights reserved.
     7 //
     8 
     9 #import <UIKit/UIKit.h>
    10 @class DeblockingView;
    11 @protocol DeblockingViewDelegate <NSObject>
    12 @optional
    13 - (void)selectBtn:(DeblockingView *)deblockingView andSelectPwd:(NSString *)pwd;
    14 
    15 @end
    16 @interface DeblockingView : UIView
    17 @property (nonatomic,assign) id<DeblockingViewDelegate> delegate;
    18 @end
      1 //
      2 //  DeblockingView.m
      3 //  1-4-Deblocking
      4 //
      5 //  Created by xiaomoge on 15/1/4.
      6 //  Copyright (c) 2015年 xiaomoge. All rights reserved.
      7 //
      8 
      9 #import "DeblockingView.h"
     10 @interface DeblockingView ()
     11 /*
     12  选中的按钮数组
     13  */
     14 @property (nonatomic,strong) NSMutableArray *selectedBtns;
     15 /*
     16  最后触摸到的点
     17  */
     18 @property (nonatomic,assign) CGPoint lastPoint;
     19 @end
     20 @implementation DeblockingView
     21 //懒加载
     22 - (NSMutableArray *)selectedBtns {
     23     if (!_selectedBtns) {
     24         _selectedBtns = [NSMutableArray array];
     25     }
     26     return _selectedBtns;
     27 }
     28 //绘制选中按钮间的连线
     29 - (void)drawRect:(CGRect)rect {
     30     //取得当前选中的按钮的个数
     31     NSInteger selectBtnCount = self.selectedBtns.count;
     32     //如果被选中的按钮个数为0,即返回。
     33     if (selectBtnCount == 0) return;
     34     
     35     UIBezierPath *path = [UIBezierPath bezierPath];
     36     for (NSInteger i = 0; i < selectBtnCount; i++) {
     37         //取得按钮先连接的点
     38         CGPoint btnCenter = [self.selectedBtns[i] center];
     39         if (i == 0) {//设置为起点
     40             [path moveToPoint:btnCenter];
     41         }else {//设置为连接点
     42             [path addLineToPoint:btnCenter];
     43         }
     44     }
     45     //如果最后有未选中按钮的连线点
     46     [path addLineToPoint:self.lastPoint];
     47     //设置连线的宽度
     48     path.lineWidth = 8;
     49     //设置连线的头尾样式
     50     path.lineCapStyle = kCGLineCapRound;
     51     //设置连线的连接点样式
     52     path.lineJoinStyle = kCGLineJoinRound;
     53     //设置连线的颜色
     54     [[UIColor greenColor] set];
     55     //渲染
     56     [path stroke];
     57 }
     58 //加载完view后会调用这个方法
     59 - (void)layoutSubviews {
     60     [super layoutSubviews];//别忘记要写父类的方法
     61     //取得按钮的数量
     62     NSInteger btnCount = self.subviews.count;
     63     //设置按钮的宽度
     64     CGFloat btnW = 74;
     65     //设置按钮的高度
     66     CGFloat btnH = 74;
     67     //设置按钮间的间距
     68     CGFloat margin = (self.bounds.size.width - 3 * btnW) / 4;
     69     for (int i = 0; i < btnCount; i++) {
     70         //取得一个按钮
     71         UIButton *btn = self.subviews[i];
     72         //获得当前的行号
     73         int row = i / 3;
     74         //获得当前列号
     75         int culomns = i % 3;
     76         //设置按钮的X(可参考应用管理中的计算)
     77         CGFloat btnX = margin + culomns * (margin + btnW);
     78         //设置按钮的Y
     79         CGFloat btnY = margin + row * (margin + btnH);
     80         btn.frame = CGRectMake(btnX, btnY, btnW, btnH);
     81     }
     82 }
     83 //初始化方法
     84 - (instancetype)initWithFrame:(CGRect)frame {
     85     if (self = [super initWithFrame:frame]) {
     86         [self setBtns];
     87     }
     88     return self;
     89 }
     90 //设置9个按钮
     91 - (void)setBtns {
     92     for (int i = 0; i < 9; i++) {
     93         UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
     94         btn.tag = i;
     95         //设置按钮正常状态下的图片
     96         [btn setImage:[UIImage imageNamed:@"gesture_node_normal"] forState:UIControlStateNormal];
     97         //设置按钮被选中时的图片
     98         [btn setImage:[UIImage imageNamed:@"gesture_node_highlighted"] forState:UIControlStateSelected];
     99         //取消与用户的交互
    100         btn.userInteractionEnabled = NO;
    101         [self addSubview:btn];
    102     }
    103 }
    104 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    105     [self touchesMoved:touches withEvent:event];
    106 }
    107 
    108 - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
    109     //获取当前触摸点
    110     UITouch *touch = [touches anyObject];
    111     CGPoint touchPoint = [touch locationInView:touch.view];
    112     
    113     for (UIButton *btn in self.subviews) {
    114         if (CGRectContainsPoint(btn.frame, touchPoint)) {//判断触摸点是否在按钮的范围内
    115             if (btn.selected == NO) {//在按钮范围内,并且为未选中状态时
    116                 [self.selectedBtns addObject:btn];//加进选中按钮的数组
    117             }
    118             btn.selected = YES;
    119         }else {//否则设置这个点为最后的触摸点
    120             self.lastPoint = touchPoint;
    121         }
    122     }
    123     //重绘
    124     [self setNeedsDisplay];
    125 }
    126 
    127 - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
    128     //拼接选中按钮的tag作为密码
    129     NSMutableString *pwd = [NSMutableString string];
    130     for (UIButton *btn in self.selectedBtns) {
    131         [pwd appendFormat:@"%ld",btn.tag];
    132     }
    133     //如果代理实现了方法,通知代理对象
    134     if ([self.delegate respondsToSelector:@selector(selectBtn:andSelectPwd:)]) {
    135         [self.delegate selectBtn:self andSelectPwd:pwd];
    136     }
    137     //设置所有被选中的按钮为未选中状态
    138     [self.selectedBtns makeObjectsPerformSelector:@selector(setSelected:) withObject:@NO];
    139     //移除所有被选中的按钮
    140     [self.selectedBtns removeAllObjects];
    141     //重绘
    142     [self setNeedsDisplay];
    143 }
    144 @end

    最后的效果图:

  • 相关阅读:
    剑指offer——最小的K个数和数组中第K大的元素
    Leetcode刷题指南链接整理
    160. Intersection of Two Linked Lists
    100. Same Tree
    92. Reverse Linked List II
    94. Binary Tree Inorder Traversal
    79. Word Search
    78,90,Subsets,46,47,Permutations,39,40 DFS 大合集
    0x16 Tire之最大的异或对
    0x16 Tire
  • 原文地址:https://www.cnblogs.com/xiaomoge/p/4202240.html
Copyright © 2011-2022 走看看