Quartz 2D 屏幕解锁

上一节中,我讲解了利用Quartz 2D完成的涂鸦功能,其实主要是利用了贝塞尔曲线来完成的。可以发现,涂鸦效果中,绘制出来的,一般都是曲线效果。这一节,我讲解利用贝塞尔曲线画直线的案例:屏幕解锁。先看看最终效果图。

这个demo就是仿真“支付宝屏幕解锁”的效果。

1. 分析UI, 有三张图片:一张大的背景图片;手指没有滑到区域的按钮,灰白色的圈圈;手指滑到区域的按钮,高亮显示的按钮。注:按钮与按钮之间的连线,是通过代码实现的,因为有各种各样的线,图片实现不现实。

2. 代码实现分析:

1) 应该记录手指滑过的按钮;

2) 应该记录手指当前所在的位置,注意上图中,最后一根线,没有连接到任何按钮,所以手指移动的时候,它是跟着改变的,所以要实时记录当前点的坐标。

3) 当用户手指抬起时,这次的操作就应该算结束了,应该记录滑动信息及完成清屏操作。

代码实现过程:

1. 定义一个View,专门用来实现屏幕解锁功能。

@interface LockView : UIView

@end

2. 定义两个属性变量,用于存储相关信息。

@interface LockView()
/* 存放所有路径经过的button */
@property (nonatomic,strong) NSMutableArray *selectedButtons;
/* 手指所在的当前位置 */
@property (nonatomic,assign) CGPoint currentPoint;
@end

3. 初始化工作及懒加载。 需要说明的是,实现了initWithFrame 和 initWithCoder, 这样的话,不管是通过xib创建的,还是通过纯代码实现的,都可以。

#pragma mark - init
// 代码初始化调用的方法
- (id)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        [self addCircle];
    }
    return self;
}

// StoryBoard或者Xib初始化调用的方法
- (id)initWithCoder:(NSCoder *)aDecoder {
    self = [super initWithCoder:aDecoder];
    if (self) {
        [self addCircle];
    }
    return self;
}

#pragma mark - lazy load
- (NSMutableArray *)selectedButtons {
    if (_selectedButtons == nil) {
        _selectedButtons = [NSMutableArray array];
    }
    return _selectedButtons;
}

4. 界面上面按钮的创建工作, 需要说明的是 btn.userInteractionEnabled = NO; 这句代码,之所以将按钮的交互效果禁用,是为了让父控件直接响应touches... 那些方法。

#pragma mark - layout subviews
- (void)addCircle {
    for (int i=0;i<9;i++) {
        UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];

        btn.userInteractionEnabled = NO;

        [btn setBackgroundImage:[UIImage imageNamed:@"gesture_node_normal.png"] forState:UIControlStateNormal];

        [btn setBackgroundImage:[UIImage imageNamed:@"gesture_node_highlighted.png"] forState:UIControlStateSelected];

        [self addSubview:btn];
    }
}

- (void)layoutSubviews {
    [super layoutSubviews];

    int colBtnCount = 3;
    int btnCount = self.subviews.count;

    CGFloat marginX = (self.frame.size.width - colBtnCount * kImageWidth) / (colBtnCount + 1);
    CGFloat marginY = (self.frame.size.height - colBtnCount * kImageWidth) / (colBtnCount + 1);

    for (int i = 0; i < btnCount; i++) {
        int row = i / colBtnCount;
        int col = i % colBtnCount;
        UIButton *btn = self.subviews[i];
        CGFloat btnX = marginX + col * (kImageWidth + marginX);
        CGFloat btnY = marginY + row * (kImageWidth + marginY);
        CGFloat btnW = kImageWidth;
        CGFloat btnH = kImageWidth;
        btn.tag = i;
        btn.frame = CGRectMake(btnX, btnY, btnW, btnH);
    }
}

5. 触摸事件。

1) touchesBegan方法中,定义了一个currentBtn变量,用于判断当前手指是否滑动到了界面上的button,如果有的话,就将滑动到的按钮赋值给currentBtn,然后判断,按钮之前有没有被选中(currentBtn.isSelected属性),如果没有,则设置为选中,此时按钮就高亮显示了。

2) touchesMoved方法所作的事情和touchesBegan方法完全一致,所以直接调用touchesBegan方法就可以了。

3)touchesEnded方法,标志此次滑动操作已经结束,所以进行相应的清空操作就可以了。

#pragma mark - touch events
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    UITouch *touch = [touches anyObject];
    CGPoint point =  [touch locationInView:touch.view];

    self.currentPoint = CGPointZero;

    UIButton *currentBtn = nil;
    for (UIButton *btn in self.subviews) {
        if (CGRectContainsPoint(btn.frame, point)) {
            currentBtn = btn;
            break;
        }
    }

    if (currentBtn && !currentBtn.isSelected) {
        currentBtn.selected = YES;
        [self.selectedButtons addObject:currentBtn];
    } else {
        self.currentPoint = point;
    }

    [self setNeedsDisplay];
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
    [self touchesBegan:touches withEvent:event];
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
    [self.selectedButtons makeObjectsPerformSelector:@selector(setSelected:) withObject:@(NO)];
    [self.selectedButtons removeAllObjects];

    [self setNeedsDisplay];
}

6. 绘制代码。

1) 在for循环中,遍历所有存放的button,注意,第一个button应该是绘制的起点,所以调用,moveToPoint方法,而其余的应该进行连线工作addLineToPoint方法。

2)连接(为什么永远是直线? 因为path(没有保存手指触摸所经过的点)只连接最后一个按钮的中心到currentPoint这个点。而涂鸦(如果对涂鸦感兴趣的话,可以参照我上一篇博客,请点击这里)是将所有经过的点,保存在path里面,然后画出来)。

3)CGPointEqualToPoint是为了绘制不在按钮范围的线段,比如,上图中的最后一根线段,没有连上任何的按钮,所以手指移动的时候,它跟着移动。

#pragma mark - draw
- (void)drawRect:(CGRect)rect {
    if (self.selectedButtons.count == 0) return;

    UIBezierPath *path = [UIBezierPath bezierPath];
    path.lineWidth = 5;
    path.lineCapStyle = kCGLineCapRound;
    path.lineJoinStyle = kCGLineJoinRound;
    [[UIColor colorWithRed:32/255.0 green:210/255.0 blue:254/255.0 alpha:0.5] set];
    for (int i = 0; i < self.selectedButtons.count; i++) {
        UIButton *btn = self.selectedButtons[i];
        if (i==0) {
            [path moveToPoint:btn.center];
        } else {
            [path addLineToPoint:btn.center];
        }
    }

    if (CGPointEqualToPoint(self.currentPoint, CGPointZero) == NO) {
        [path addLineToPoint:self.currentPoint];
    }

    [path stroke];
}

7.  增加判断密码是否正确功能。

考虑到,这里的屏幕解锁是一个单独的功能,并且有可能多个界面复用,所以我们可以自定义代理,判断密码输入是否正确。

1)改造 LockView。

@class LockView;
@protocol LockViewDelegate<NSObject>

@optional
- (void)lockView:(LockView *)lockView didFinishPath:(NSString *)path;

@end

@interface LockView : UIView

@property (nonatomic,weak) id<LockViewDelegate> delegate;

@end

2) 在touchesEnded方法判断密码正确与否。

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
    if ([self.delegate respondsToSelector:@selector(lockView:didFinishPath:)]) {
        NSMutableString *str = [NSMutableString string];
        for (UIButton *btn in self.selectedButtons) {
            [str appendFormat:@"%ld",(long)btn.tag];
        }
        [self.delegate lockView:self didFinishPath:str];
    }

    [self.selectedButtons makeObjectsPerformSelector:@selector(setSelected:) withObject:@(NO)];
    [self.selectedButtons removeAllObjects];

    [self setNeedsDisplay];
}
时间: 2024-10-31 07:20:29

Quartz 2D 屏幕解锁的相关文章

iOS开发——图形编程OC篇&amp;(六)Quartz 2D高级使用(二)

Quartz 2D高级使用 一.绘图路径 A.简单说明 在画线的时候,方法的内部默认创建一个path.它把路径都放到了path里面去. 1.创建路径  cgmutablepathref 调用该方法相当于创建了一个路径,这个路径用来保存绘图信息. 2.把绘图信息添加到路径里边. 以前的方法是点的位置添加到ctx(图形上下文信息)中,ctx 默认会在内部创建一个path用来保存绘图信息. 在图形上下文中有一块存储空间专门用来存储绘图信息,其实这块空间就是CGMutablePathRef. 3.把路径

iOS开发——图形编程OC篇&amp;(一)Quartz 2D介绍

Quartz 2D介绍 一.什么是Quartz2D Quartz 2D是?个二维绘图引擎,同时支持iOS和Mac系统 Quartz 2D能完成的工作: 绘制图形 : 线条\三角形\矩形\圆\弧等 绘制文字 绘制\生成图片(图像) 读取\生成PDF 截图\裁剪图片 自定义UI控件 二.Quartz2D在iOS开发中的价值 为了便于搭建美观的UI界面,iOS提供了UIKit框架,??有各种各样的UI控件 UILabel:显?文字 UIImageView:显示图片 UIButton:同时显示图片和?字

Quartz 2D简介

1.Quartz 2D是一种二维绘图库,它与iphone OS紧密结合在一起,能协同所有相关框架进行工作,包括Core Animation.OpenGL ES和UIKit. 2.Quartz的绘图功能取决与3个核心概念:上下文.路径和状态. ①上下文(context):用户描述将图形写入哪里,该过程由CGContextRef定义.通常,可以写入UIView或位图中. ②路径:路径是那些经常在Quartz中绘制的内容.起初,他们是线段和弧的集合,随后通过描边或填充的方式绘制到屏幕中. ③状态:状态

IOS开发—Quartz 2D介绍

Quartz 2D学习记录 Quartz 2D简单介绍 一.什么是Quartz 2D Quarz 2D是一个二维绘画引擎,同时支持ios和mac,其API是Core Graphics框架的,是纯C语言的.IOS系统提供的大部分控件的内容都是通过Quartz 2D画出来的,因此Quartz 2D的一个很重要的价值是:自定义view(自定义UI控件). 二.一个重要的概念:图形上下文 图形上下文(Graphics context)是一个CGContextRef数据,其作用是: 保存绘图信息.绘图属性

iOS开发——图层OC篇&amp;Quartz 2D各种绘制实例

Quartz 2D各种绘制实例 首先说一下,本篇文章只是介绍怎么使用Quartz 2D绘制一些常用的图像效果,关于Quartz和其他相关技术请查看笔者之前写的完整版(Quartz 2D详解) 一:画线 1 // 1.获取跟当前View相关联的layer上下文(画板) 2 // 总结:目前获取的所有上下文都是以UIGraphics开头 3 // CGContextRef:上下文类型 4 // CG:CoreGraphics Ref:引用 5 CGContextRef ctx = UIGraphic

iOS 开发 Quartz 2D+ UIBezierPath绘图大全详解

Quartz 2D 使用大全结构图 UIKIt UIBezierPath Core Graphics OpenGL ES Quartz2D的区别和联系 UIKIt:UIKit中的控件都是基于Core Graphics实现的 UIBezierPath:UIBezierPath属于UIKit,它是苹果对复杂的Core Graphics进行的封装,方便我们用OC语言进行简单的绘图 Core Graphics:是一套基于C语言的API,支持向量图形,线.形状.图案.路径.剃度.位图图像和pdf 内容的绘

1.0 Quartz 2D简介

Quartz2D须知: (1)Quartz 2D是苹果官方的二维绘图引擎,同时支持iOS和Mac OS X系统(跨平台,纯 C 语言的) (2)Quartz2D的API是纯C语言的 (3)Quartz2D的API来自于Core Graphics框架         (4)数据类型和函数基本都以CG作为前缀 CGContextRef —— 图形上下文(相当于一个草稿纸) CGPathRef  ——— 图形路径 CGContextStrokePath(cox);   ——— 渲染 Quartz2D 

Quartz 2D编程指南(2) - 图形上下文

一个Graphics Context表示一个绘制目标.它包含绘制系统用于完成绘制指令的绘制参数和设备相关信息.Graphics Context定义了基本的绘制属性,如颜色.裁减区域.线条宽度和样式信息.字体信息.混合模式等. 我们可以通过几种方式来获取Graphics Context:Quartz提供的创建函数.Mac OS X框架或IOS的UIKit框架提供的函数.Quartz提供了多种Graphics Context的创建函数,包括bitmap和PDF,我们可以使用这些Graphics Co

绘图与滤镜全面解析--Quartz 2D 、Core Image

绘图与滤镜全面解析 概述 在iOS中可以很容易的开发出绚丽的界面效果,一方面得益于成功系统的设计,另一方面得益于它强大的开发框架.今天我们将围绕iOS中两大图形.图像绘图框架进行介绍:Quartz 2D绘制2D图形和Core Image中强大的滤镜功能. Quartz 2D 基本图形绘制 视图刷新 其他图形上下文 Core Image Quartz 2D 在iOS中常用的绘图框架就是Quartz 2D,Quartz 2D是Core Graphics框架的一部分,是一个强大的二维图像绘制引擎.Qu