画板与手势解锁

画板

利用触摸功能可以与drawRect可以实现画板。

由于数组中只能存对象,所以不能用CGMutablePathRef来存储路径,使用UIBezierPath即可。UIBezierPath相当于CGMutablePathRef的OC版本。

原理:
将触碰的每一个点存入数组,在drawRect中根据数组全部重新绘制一遍。
所以清屏只要移除数组中的所有元素即可,回退则删除数组最后一个元素。

主体代码:

// 开始触摸
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{

    // 1.获取手指对应UITouch对象
    UITouch *touch = [touches anyObject];
    // 2.通过UITouch对象获取手指触摸的位置
    CGPoint startPoint = [touch locationInView:touch.view];

    // 3.当用户手指按下的时候创建一条路径
    UIBezierPath *path = [UIBezierPath bezierPath];
    // 3.1设置路径的相关属性
    [path setLineJoinStyle:kCGLineJoinRound];
    [path setLineCapStyle:kCGLineCapRound];
    [path setLineWidth:10];


    // 4.设置当前路径的起点
    [path moveToPoint:startPoint];
    // 5.将路径添加到数组中
    [self.paths addObject:path];   
}

// 移动
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    // 1.获取手指对应UITouch对象
    UITouch *touch = [touches anyObject];
    // 2.通过UITouch对象获取手指触摸的位置
    CGPoint movePoint = [touch locationInView:touch.view];

    // 3.取出当前的path
    UIBezierPath *currentPaht = [self.paths lastObject];
    // 4.设置当前路径的终点
    [currentPaht addLineToPoint:movePoint];

    // 6.调用drawRect方法重回视图
    [self setNeedsDisplay];
}

// 离开view(停止触摸)
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{

    [self touchesMoved:touches withEvent:event];
}
// 画线
- (void)drawRect:(CGRect)rect
{
    [[UIColor redColor] set];
    // 边路数组绘制所有的线段
    for (UIBezierPath *path in self.paths) {
        [path stroke];
    }  
}

手势解锁

原理:
根据接触点是否在按键的frame内判断按键选中状态,并记录当前接触点
根据按键的选中状态,将按键添加入数组
连接数组中按键的中点,然后如果按键数组不为空则添加与当前接触点的连线
离开屏幕时清除数组以去除连线,重置选中状态

主要代码:

@property (nonatomic, strong) NSMutableArray *buttons;
/** * 定义属性,记录用户当前手指的位置(非按钮范围内) */
@property (nonatomic, assign) CGPoint currentPoint;
- (NSMutableArray *)buttons
{
    if (nil == _buttons) {
        _buttons = [NSMutableArray array];
    }

    return _buttons;
}

- (void)setup
{
    for (int i = 0; i < 9; i++) {
        UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
        // 禁止按钮的点击事件(因为我们需要监听触摸事件)
        button.userInteractionEnabled = NO;
        [self addSubview:button];
    }
}

- (void)layoutSubviews
{
    UIImage *imageNormal = [UIImage imageNamed:@"gesture_node_normal"];
    UIImage *imageSelected = [UIImage imageNamed:@"gesture_node_highlighted"];

    float gapX = (self.frame.size.width - 3 * imageNormal.size.width) / 4.0;
    float gapY = gapX;

    CGSize buttonSize = imageNormal.size;

    for (int i = 0; i < 9; i++) {
        UIButton *button = self.subviews[i];

        [button setBackgroundImage:imageNormal forState:UIControlStateNormal];
        [button setBackgroundImage:imageSelected forState:UIControlStateSelected];

        float buttonX = gapX + i % 3 * (buttonSize.width + gapX);
        float buttonY = gapY + i / 3 * (buttonSize.height + gapY);

        button.frame = CGRectMake(buttonX, buttonY, buttonSize.width, buttonSize.height);
    }
}
// 通过xib或者storyboard加载时调用
- (id)initWithCoder:(NSCoder *)aDecoder
{
    if (self = [super initWithCoder:aDecoder]) {
        [self setup];
        self.backgroundColor = [UIColor clearColor];
    }

    return self;
}

// 通过代码创建时调用
- (instancetype)initWithFrame:(CGRect)frame
{
    if (self = [super initWithFrame:frame]) {
        [self setup];
        self.backgroundColor = [UIColor clearColor];
    }

    return self;
}
/** * 根据触摸点获取触摸到的按钮 * @return 触摸的按钮 */
- (UIButton *)getCurrentBtnWithPoint:(CGPoint)point
{
    // 判断触摸的位置是否在按钮的范围内
    for (UIButton *btn in self.subviews) {
        // rect是否包含point
        if (CGRectContainsPoint(btn.frame, point)) {
            return btn;
        }
    }
    return nil;
}

/** * 根据系统传入的UITouch集合获取当前触摸的点 * @return 当初触摸的点 */
- (CGPoint)getCurrentTouchPoint:(NSSet *)touches
{
    // 获取按下的点
    UITouch *touch =  [touches anyObject];
    CGPoint point = [touch locationInView:touch.view];
    return point;
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    // 1.获取按下的点
   CGPoint startPoint = [self getCurrentTouchPoint:touches];

    // 2.判断触摸的位置是否在按钮的范围内
    UIButton *btn = [self getCurrentBtnWithPoint:startPoint];

    // 存储按钮
    if (btn)
    {
        // 设置选中状态
        btn.selected = YES;
        // 将按钮保存到数组中
        [self.buttons addObject:btn];
    }
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    // 1.获取按下的点
    CGPoint movePoint = [self getCurrentTouchPoint:touches];
    // 2.获取触摸的按钮
    UIButton *btn = [self getCurrentBtnWithPoint:movePoint];

    // 存储按钮
    if (btn && btn.selected != YES)
    {
        // 设置选中状态
        btn.selected = YES;
        // 将按钮保存到数组中
        [self.buttons addObject:btn];
    }
    // 记录当前手指移动的位置
    self.currentPoint = movePoint;

    // 通知view绘制线段
    [self setNeedsDisplay];

}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    // 遍历数组并对其中的每个元素调用setSelected:方法
    // 去除选中状态
    [self.buttons makeObjectsPerformSelector:@selector(setSelected:) withObject:@(NO)];

    // 清空数组,清楚连线
    [self.buttons removeAllObjects];
    [self setNeedsDisplay];
}

- (void)drawRect:(CGRect)rect
{
    CGContextRef ctf = UIGraphicsGetCurrentContext();

    CGContextSetLineWidth(ctf, 15.0);
    CGContextSetLineCap(ctf, kCGLineCapRound);
    CGContextSetLineJoin(ctf, kCGLineJoinRound);
    [[UIColor colorWithRed:10 / 255.0 green:100 / 255.0 blue:50 / 255.0 alpha:0.5] set];

    for (int i = 0; i < self.buttons.count; i++) {
        CGPoint center = [self.buttons[i] center];

        if (0 == i) {
            CGContextMoveToPoint(ctf, center.x, center.y);
        } else {
            CGContextAddLineToPoint(ctf, center.x, center.y);
        }
    }

    // 不能用判断这个点是不是0,0来决定,即使end那里清零这个点,在进行快速点击时,还是会发生错误,坐标会出现不为0的情况。
// if (!CGPointEqualToPoint(CGPointZero, self.currentPoint)) {
// CGContextAddLineToPoint(ctf, self.currentPoint.x, self.currentPoint.y);
// }
// 判断数组中是否有按钮, 如果有按钮就有起点, 有起点就不会报错
    if (self.buttons.count) {
        CGContextAddLineToPoint(ctf, self.currentPoint.x, self.currentPoint.y);
    }

    CGContextStrokePath(ctf);
}

需要输出密码时,可设置button的tag,并设置代理,在end时将密码传出,由控制器进行判断密码是否正确等操作

你可能感兴趣的:(画板与手势解锁)