Quartz 2D之手势解锁(支付宝)
2016-04-12 19:05
363 查看
仿造支付宝写的一个手势解锁的Demo,那么废话不多说直接上代码!
//
// ViewController.h
// Quartz 2D - 手势解锁
//
// Created by 周昭 on 16/4/12.
// Copyright © 2016年 Jordan Zhou. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface ViewController :
UIViewController
@end
//
// ViewController.m
// Quartz 2D - 手势解锁
//
// Created by 周昭 on 16/4/12.
// Copyright © 2016年 Jordan Zhou. All rights reserved.
//
#import "ViewController.h"
#import "ZZLockView.h"
@interface
ViewController ()<ZZLockViewDelegate>
@end
@implementation ViewController
- (void)viewDidLoad {
[super
viewDidLoad];
//
设置背景
[self
setUpBackImg];
//
添加lockView
[self
setUpLockView];
}
/**
* 设置背景
*/
- (void)setUpBackImg
{
UIImageView *bgImg = [[UIImageView
alloc]
initWithFrame:self.view.frame];
bgImg.image = [UIImage
imageNamed:@"Home_refresh_bg"];
[self.view
addSubview:bgImg];
}
/**
* 添加lockView
*/
- (void)setUpLockView
{
ZZLockView *lockView = [[ZZLockView
alloc] init];
lockView.delegate =
self;
lockView.backgroundColor = [UIColor
clearColor];
lockView.center =
CGPointMake(self.view.frame.size.width
* 0.5,
self.view.frame.size.height *
0.5);
lockView.bounds =
CGRectMake(0,
0, self.view.frame.size.width,
self.view.frame.size.height);
[self.view
addSubview:lockView];
}
/**
* 代理方法
*/
- (void)lockView:(ZZLockView *)lockView didFinishPath:(NSString *)path
{
NSLog(@"拿到我们的path进行操作进行对比");
}
@end
//
// ZZLockView.h
// Quartz 2D - 手势解锁
//
// Created by 周昭 on 16/4/12.
// Copyright © 2016年 Jordan Zhou. All rights reserved.
//
#import <UIKit/UIKit.h>
@class ZZLockView;
@protocol ZZLockViewDelegate <NSObject>
@optional
- (void)lockView:(ZZLockView *)lockView didFinishPath:(NSString *)path;
@end
@interface ZZLockView :
UIView
@property (nonatomic,
weak) id <ZZLockViewDelegate> delegate;
@end
//
// ZZLockView.m
// Quartz 2D - 手势解锁
//
// Created by 周昭 on 16/4/12.
// Copyright © 2016年 Jordan Zhou. All rights reserved.
//
#import "ZZLockView.h"
#import "ZZCircleBtn.h"
@interface ZZLockView()
@property (nonatomic,
strong) NSMutableArray *selectedButtons;
@property (nonatomic,
assign) CGPoint currentMovePoint;
@end
@implementation ZZLockView
- (NSMutableArray *)selectedButtons
{
if (!_selectedButtons) {
_selectedButtons = [NSMutableArray
array];
}
return
_selectedButtons;
}
/**
* 初始化
*/
- (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super
initWithFrame:frame]) {
[self setUp];
}
return
self;
}
/**
* 无论你从什么创建Xib\代码创建都可以
*/
- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
if (self = [super
initWithCoder:aDecoder]) {
[self setUp];
}
return
self;
}
/**
* 添加按钮
*/
- (void)setUp
{
for (int index =
0; index < 9; index++) {
#pragma mark --- 封装一层封装一层circleBtn
// 创建背景
ZZCircleBtn *btn = [ZZCircleBtn
buttonWithType:UIButtonTypeCustom];
// 绑定tag得到路径(所以这里我们在数组中存的直接是这个按钮\当然你存按钮的中点也是可以的但是路径呢?)
btn.tag = index;
// 添加按钮
[self addSubview:btn];
}
}
/**
* 已经添加那么在这里设置他的frame
*/
- (void)layoutSubviews
{
for (int index =
0; index < self.subviews.count; index++) {
// 取出按钮
ZZCircleBtn *btn =
self.subviews[index];
int totolColumns =
3;
int col = index % totolColumns;
int row = index / totolColumns;
CGFloat btnW =
74;
CGFloat btnH =
74;
CGFloat marginX = (self.frame.size.width - totolColumns * btnW) / (totolColumns
+ 1);
CGFloat marginY = marginX;
CGFloat btnX = marginX + col * (marginX + btnW);
CGFloat btnY = marginY + row * (marginY + btnH);
btn.frame =
CGRectMake(btnX, btnY, btnW, btnH);
}
}
#pragma mark ---- 私有方法
/**
* 根据touches的集合获得对应触摸点的位置
*/
- (CGPoint)pointWithTouches:(NSSet *)touches
{
// 1.取出按钮的点
UITouch *touch = [touches
anyObject];
return [touch
locationInView:touch.view];
}
/**
* 根据我们的触摸点判断是不是选中的按钮
*/
- (ZZCircleBtn *)buttonWithPoint:(CGPoint)point
{
//
遍历 CGRectContainsPoint(btn.frame, pos)
返回BOOL值
看这个点在不在这个范围内
for (ZZCircleBtn *btn
in self.subviews) {
#pragma mark ---- 判断到圆心的才连接
CGFloat wh =
24;
CGFloat frameX = btn.center.x - wh *
0.5;
CGFloat frameY = btn.center.y - wh *
0.5;
if (CGRectContainsPoint(CGRectMake(frameX, frameY, wh, wh), point)) {
return btn;
}
}
return
nil;
}
#pragma mark ---- 触摸方法
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
// 0.我们一按下去就把这个点清空
self.currentMovePoint =
CGPointZero;
// 1.获得触摸点
CGPoint pos = [self
pointWithTouches:touches];
// 2.获得触摸的按钮
ZZCircleBtn *btn = [self
buttonWithPoint:pos];
if (btn && btn.selected ==
NO) {
// 3.按钮被选中
btn.selected =
YES;
// 4.添加到数组中(如果你直接这么写一看就没经验 [self.selectedButtons addObject:btn]; btn
可能为空
所有以后数组和字典中添加东西一定判断为不为空)
[self.selectedButtons
addObject:btn];
}
}
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
// 1.获得触摸点
CGPoint pos = [self
pointWithTouches:touches];
// 2.获得触摸的按钮
ZZCircleBtn *btn = [self
buttonWithPoint:pos];
if (btn && btn.selected ==
NO) {
// 3.按钮被选中
btn.selected =
YES;
// 4.添加到数组中(如果你直接这么写一看就没经验 [self.selectedButtons addObject:btn]; btn
可能为空
所有以后数组和字典中添加东西一定判断为不为空)
[self.selectedButtons
addObject:btn];
} else { //
没有摸到按钮
self.currentMovePoint = pos;
}
// 5.刷新
[self
setNeedsDisplay];
}
/**
* 触摸结束
*/
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
if ([self.delegate
respondsToSelector:@selector(lockView:didFinishPath:)]) {
//
得到画的路径
NSMutableString *path = [NSMutableString
string];
for (ZZCircleBtn *btn
in self.selectedButtons) {
[path appendFormat:@"%ld",btn.tag];
}
NSLog(@"%@",path);
[self.delegate
lockView:self
didFinishPath:path];
}
// 取消选中的所有按钮\能尽量优化的时候就应该优化那么这里没必要遍历所有的子控件
for (ZZCircleBtn *btn
in self.selectedButtons) {
btn.selected =
NO;
}
// 让所有的按钮都执行这个方法 \
注意最后一个返回值一定要包装成对象就行
// [self.selectedButtons makeObjectsPerformSelector:@selector(setSelected:) withObject:@(NO)];
[self.selectedButtons
removeAllObjects];
[self
setNeedsDisplay];
}
/**
* 触摸被打破我们直接调用touchesEnded的方法
*/
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
[self touchesEnded:touches
withEvent:event];
}
#pragma mark --- 绘图
- (void)drawRect:(CGRect)rect
{
if (self.selectedButtons.count ==
0) return;
UIBezierPath *path = [UIBezierPath
bezierPath];
for (int index =
0; index < self.selectedButtons.count; index++) {
ZZCircleBtn *btn =
self.selectedButtons[index];
if (index ==
0) {
[path moveToPoint:btn.center];
} else {
[path addLineToPoint:btn.center];
}
}
// 如果当前点没有那么我们就要清除
if (CGPointEqualToPoint(self.currentMovePoint,
CGPointZero) ==
NO) {
[path addLineToPoint:self.currentMovePoint];
}
//
设置连接样式
path.lineJoinStyle =
kCGLineJoinBevel;
path.lineWidth =
10;
[[UIColor
colorWithRed:32/255.0
green:210/255.0
blue:254/255.0
alpha:0.7]
set];
[path stroke];
}
@end
//
// ZZCircleBtn.h
// Quartz 2D - 手势解锁
//
// Created by 周昭 on 16/4/12.
// Copyright © 2016年 Jordan Zhou. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface ZZCircleBtn :
UIButton
@end
//
// ZZCircleBtn.m
// Quartz 2D - 手势解锁
//
// Created by 周昭 on 16/4/12.
// Copyright © 2016年 Jordan Zhou. All rights reserved.
//
#import "ZZCircleBtn.h"
@implementation ZZCircleBtn
/**
* 初始化
*/
- (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super
initWithFrame:frame]) {
[self setUp];
}
return
self;
}
/**
* 无论你从什么创建Xib\代码创建都可以
*/
- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
if (self = [super
initWithCoder:aDecoder]) {
[self setUp];
}
return
self;
}
/**
* 添加按钮
*/
- (void)setUp
{
// 直接让按钮不能响应事件否则按钮长按会变色
self.userInteractionEnabled =
NO;
// 设置默认按钮图片
[self
setBackgroundImage:[UIImage
imageNamed:@"gesture_node_normal"]
forState:UIControlStateNormal];
// 设置选中是按钮的图片(为什么是selected?当你的按钮离开的时候就不是highlighted所以要选中)
[self
setBackgroundImage:[UIImage
imageNamed:@"gesture_node_highlighted"]
forState:UIControlStateSelected];
}
@end
//
// ViewController.h
// Quartz 2D - 手势解锁
//
// Created by 周昭 on 16/4/12.
// Copyright © 2016年 Jordan Zhou. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface ViewController :
UIViewController
@end
//
// ViewController.m
// Quartz 2D - 手势解锁
//
// Created by 周昭 on 16/4/12.
// Copyright © 2016年 Jordan Zhou. All rights reserved.
//
#import "ViewController.h"
#import "ZZLockView.h"
@interface
ViewController ()<ZZLockViewDelegate>
@end
@implementation ViewController
- (void)viewDidLoad {
[super
viewDidLoad];
//
设置背景
[self
setUpBackImg];
//
添加lockView
[self
setUpLockView];
}
/**
* 设置背景
*/
- (void)setUpBackImg
{
UIImageView *bgImg = [[UIImageView
alloc]
initWithFrame:self.view.frame];
bgImg.image = [UIImage
imageNamed:@"Home_refresh_bg"];
[self.view
addSubview:bgImg];
}
/**
* 添加lockView
*/
- (void)setUpLockView
{
ZZLockView *lockView = [[ZZLockView
alloc] init];
lockView.delegate =
self;
lockView.backgroundColor = [UIColor
clearColor];
lockView.center =
CGPointMake(self.view.frame.size.width
* 0.5,
self.view.frame.size.height *
0.5);
lockView.bounds =
CGRectMake(0,
0, self.view.frame.size.width,
self.view.frame.size.height);
[self.view
addSubview:lockView];
}
/**
* 代理方法
*/
- (void)lockView:(ZZLockView *)lockView didFinishPath:(NSString *)path
{
NSLog(@"拿到我们的path进行操作进行对比");
}
@end
//
// ZZLockView.h
// Quartz 2D - 手势解锁
//
// Created by 周昭 on 16/4/12.
// Copyright © 2016年 Jordan Zhou. All rights reserved.
//
#import <UIKit/UIKit.h>
@class ZZLockView;
@protocol ZZLockViewDelegate <NSObject>
@optional
- (void)lockView:(ZZLockView *)lockView didFinishPath:(NSString *)path;
@end
@interface ZZLockView :
UIView
@property (nonatomic,
weak) id <ZZLockViewDelegate> delegate;
@end
//
// ZZLockView.m
// Quartz 2D - 手势解锁
//
// Created by 周昭 on 16/4/12.
// Copyright © 2016年 Jordan Zhou. All rights reserved.
//
#import "ZZLockView.h"
#import "ZZCircleBtn.h"
@interface ZZLockView()
@property (nonatomic,
strong) NSMutableArray *selectedButtons;
@property (nonatomic,
assign) CGPoint currentMovePoint;
@end
@implementation ZZLockView
- (NSMutableArray *)selectedButtons
{
if (!_selectedButtons) {
_selectedButtons = [NSMutableArray
array];
}
return
_selectedButtons;
}
/**
* 初始化
*/
- (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super
initWithFrame:frame]) {
[self setUp];
}
return
self;
}
/**
* 无论你从什么创建Xib\代码创建都可以
*/
- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
if (self = [super
initWithCoder:aDecoder]) {
[self setUp];
}
return
self;
}
/**
* 添加按钮
*/
- (void)setUp
{
for (int index =
0; index < 9; index++) {
#pragma mark --- 封装一层封装一层circleBtn
// 创建背景
ZZCircleBtn *btn = [ZZCircleBtn
buttonWithType:UIButtonTypeCustom];
// 绑定tag得到路径(所以这里我们在数组中存的直接是这个按钮\当然你存按钮的中点也是可以的但是路径呢?)
btn.tag = index;
// 添加按钮
[self addSubview:btn];
}
}
/**
* 已经添加那么在这里设置他的frame
*/
- (void)layoutSubviews
{
for (int index =
0; index < self.subviews.count; index++) {
// 取出按钮
ZZCircleBtn *btn =
self.subviews[index];
int totolColumns =
3;
int col = index % totolColumns;
int row = index / totolColumns;
CGFloat btnW =
74;
CGFloat btnH =
74;
CGFloat marginX = (self.frame.size.width - totolColumns * btnW) / (totolColumns
+ 1);
CGFloat marginY = marginX;
CGFloat btnX = marginX + col * (marginX + btnW);
CGFloat btnY = marginY + row * (marginY + btnH);
btn.frame =
CGRectMake(btnX, btnY, btnW, btnH);
}
}
#pragma mark ---- 私有方法
/**
* 根据touches的集合获得对应触摸点的位置
*/
- (CGPoint)pointWithTouches:(NSSet *)touches
{
// 1.取出按钮的点
UITouch *touch = [touches
anyObject];
return [touch
locationInView:touch.view];
}
/**
* 根据我们的触摸点判断是不是选中的按钮
*/
- (ZZCircleBtn *)buttonWithPoint:(CGPoint)point
{
//
遍历 CGRectContainsPoint(btn.frame, pos)
返回BOOL值
看这个点在不在这个范围内
for (ZZCircleBtn *btn
in self.subviews) {
#pragma mark ---- 判断到圆心的才连接
CGFloat wh =
24;
CGFloat frameX = btn.center.x - wh *
0.5;
CGFloat frameY = btn.center.y - wh *
0.5;
if (CGRectContainsPoint(CGRectMake(frameX, frameY, wh, wh), point)) {
return btn;
}
}
return
nil;
}
#pragma mark ---- 触摸方法
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
// 0.我们一按下去就把这个点清空
self.currentMovePoint =
CGPointZero;
// 1.获得触摸点
CGPoint pos = [self
pointWithTouches:touches];
// 2.获得触摸的按钮
ZZCircleBtn *btn = [self
buttonWithPoint:pos];
if (btn && btn.selected ==
NO) {
// 3.按钮被选中
btn.selected =
YES;
// 4.添加到数组中(如果你直接这么写一看就没经验 [self.selectedButtons addObject:btn]; btn
可能为空
所有以后数组和字典中添加东西一定判断为不为空)
[self.selectedButtons
addObject:btn];
}
}
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
// 1.获得触摸点
CGPoint pos = [self
pointWithTouches:touches];
// 2.获得触摸的按钮
ZZCircleBtn *btn = [self
buttonWithPoint:pos];
if (btn && btn.selected ==
NO) {
// 3.按钮被选中
btn.selected =
YES;
// 4.添加到数组中(如果你直接这么写一看就没经验 [self.selectedButtons addObject:btn]; btn
可能为空
所有以后数组和字典中添加东西一定判断为不为空)
[self.selectedButtons
addObject:btn];
} else { //
没有摸到按钮
self.currentMovePoint = pos;
}
// 5.刷新
[self
setNeedsDisplay];
}
/**
* 触摸结束
*/
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
if ([self.delegate
respondsToSelector:@selector(lockView:didFinishPath:)]) {
//
得到画的路径
NSMutableString *path = [NSMutableString
string];
for (ZZCircleBtn *btn
in self.selectedButtons) {
[path appendFormat:@"%ld",btn.tag];
}
NSLog(@"%@",path);
[self.delegate
lockView:self
didFinishPath:path];
}
// 取消选中的所有按钮\能尽量优化的时候就应该优化那么这里没必要遍历所有的子控件
for (ZZCircleBtn *btn
in self.selectedButtons) {
btn.selected =
NO;
}
// 让所有的按钮都执行这个方法 \
注意最后一个返回值一定要包装成对象就行
// [self.selectedButtons makeObjectsPerformSelector:@selector(setSelected:) withObject:@(NO)];
[self.selectedButtons
removeAllObjects];
[self
setNeedsDisplay];
}
/**
* 触摸被打破我们直接调用touchesEnded的方法
*/
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
[self touchesEnded:touches
withEvent:event];
}
#pragma mark --- 绘图
- (void)drawRect:(CGRect)rect
{
if (self.selectedButtons.count ==
0) return;
UIBezierPath *path = [UIBezierPath
bezierPath];
for (int index =
0; index < self.selectedButtons.count; index++) {
ZZCircleBtn *btn =
self.selectedButtons[index];
if (index ==
0) {
[path moveToPoint:btn.center];
} else {
[path addLineToPoint:btn.center];
}
}
// 如果当前点没有那么我们就要清除
if (CGPointEqualToPoint(self.currentMovePoint,
CGPointZero) ==
NO) {
[path addLineToPoint:self.currentMovePoint];
}
//
设置连接样式
path.lineJoinStyle =
kCGLineJoinBevel;
path.lineWidth =
10;
[[UIColor
colorWithRed:32/255.0
green:210/255.0
blue:254/255.0
alpha:0.7]
set];
[path stroke];
}
@end
//
// ZZCircleBtn.h
// Quartz 2D - 手势解锁
//
// Created by 周昭 on 16/4/12.
// Copyright © 2016年 Jordan Zhou. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface ZZCircleBtn :
UIButton
@end
//
// ZZCircleBtn.m
// Quartz 2D - 手势解锁
//
// Created by 周昭 on 16/4/12.
// Copyright © 2016年 Jordan Zhou. All rights reserved.
//
#import "ZZCircleBtn.h"
@implementation ZZCircleBtn
/**
* 初始化
*/
- (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super
initWithFrame:frame]) {
[self setUp];
}
return
self;
}
/**
* 无论你从什么创建Xib\代码创建都可以
*/
- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
if (self = [super
initWithCoder:aDecoder]) {
[self setUp];
}
return
self;
}
/**
* 添加按钮
*/
- (void)setUp
{
// 直接让按钮不能响应事件否则按钮长按会变色
self.userInteractionEnabled =
NO;
// 设置默认按钮图片
[self
setBackgroundImage:[UIImage
imageNamed:@"gesture_node_normal"]
forState:UIControlStateNormal];
// 设置选中是按钮的图片(为什么是selected?当你的按钮离开的时候就不是highlighted所以要选中)
[self
setBackgroundImage:[UIImage
imageNamed:@"gesture_node_highlighted"]
forState:UIControlStateSelected];
}
@end
相关文章推荐
- JSP的原理、JSP的执行过程
- 计算机网络-IP类型判断
- java中堆和栈的区别
- 软件工程作业04
- TransactionProxyFactoryBean 代理事务 $Proxy9 cannot be cast to异常解决方法
- Ubuntu14.10下LAMP的环境配置
- 数据库自增字段是字符型的简单处理
- java.lang.NoClassDefFoundError: * : Landroid/support/v7/gridlayout/R$styleable 异常终极解决办法
- 分享某公司JAVA实习生招聘代码面的一道题
- 山东省第四届ACM大学生程序设计竞赛 Boring Counting 划分树
- AsynTask源码总结
- 20145238-荆玉茗 《Java程序设计》第7周学习总结
- bell-manford判负环模板
- jsp和exclipse还有myexclipse+mysql+sqlserver
- 一种夸域名web单点登录设计思路
- Net分布式系统之一:系统整体框架介绍
- Spring与Mybatis三种常用整合方法
- openfire 成功安装后无法启动,无法访问http://ip:9090
- Android自定义控件1
- NYOJ-23 取石子(一)