仿造支付宝写的一个手势解锁的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