iOS Quartz2D实战系列-手把手教你手势解锁
2016-08-18 12:59
288 查看
手势解锁
这是我模仿的QQ手势解锁部分界面~
密码输入错误效果
密码输入正确效果
界面粗糙,还请海涵~
接下来开始上代码了~
我是自定义了一个SpeedDailView继承于UIView的九宫格界面
解释都在注释里了
SpeedDialView.h
#import <UIKit/UIKit.h>
@interface SpeedDialView : UIView
//用来盛放选中的button
@property (nonatomic,retain) NSMutableArray *btns;
//输入的密码
@property (nonatomic,strong) NSMutableString *code;
//正确密码
@property (nonatomic,strong) NSString *password;
//触摸是否结束
@property (nonatomic,assign) BOOL isEnd;
@end
SpeedDialView.m
#import "SpeedDialView.h"
@implementation SpeedDialView
- (instancetype)init
{
self = [super init];
if (self) {
}
return self;
}
//懒加载
- (NSMutableArray *)btns
{
if (!_btns) {
self.btns = [[NSMutableArray alloc]init];
}
return _btns;
}
//创建9个按钮
- (void)setUpBasicUI
{
for (int i = 0; i < 9; i++) {
UIButton *btn = [UIButton buttonWithType:(UIButtonTypeCustom)];
btn.tag = i;
[self addSubview:btn];
}
}
//设置9个按钮的位置
- (void)layoutSubviews
{
[super layoutSubviews];
//这个方法只运行一次
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[self setUpBasicUI];
});
//经典的9宫格算法
int totalColume = 3;
CGFloat bWidth = 74;
CGFloat bHeight = bWidth;
CGFloat margin = (self.frame.size.width - bWidth * totalColume)/(totalColume + 1);
for (int i = 0; i< self.subviews.count; i++) {
int currentRow = i/totalColume;
int currentColumn = i%totalColume;
CGFloat originX = margin + (currentColumn * (margin + bWidth));
CGFloat originY = currentRow * (margin + bHeight);
//设置Button的外观和大小
UIButton *btn = self.subviews[i];
[btn setImage:[UIImage imageNamed:@"xv"] forState:(UIControlStateNormal)];
[btn setImage:[UIImage imageNamed:@"shi"] forState:(UIControlStateSelected)];
btn.contentMode = UIViewContentModeCenter;
btn.userInteractionEnabled = false;
btn.frame = CGRectMake(originX, originY, bWidth, bHeight);
}
}
//获取当前的触摸点的坐标
- (CGPoint)pointWithTouches:(NSSet<UITouch *> *)touches
{
UITouch *touch = [touches anyObject];
CGPoint point = [touch locationInView:touch.view];
return point;
}
//判断当前点在不在Button中
- (UIButton *)buttonWithPoint:(CGPoint)point
{
for (int i = 0; i < self.subviews.count; i++) {
UIButton *btn = self.subviews[i];
CGFloat wh = btn.frame.size.width - 5;
//找到Button中心附近25*25的面积
CGFloat frameX = btn.center.x - wh * 0.5;
CGFloat frameY = btn.center.y - wh * 0.5;
//判断这个点在button中心附近25*25的面积内的话就是它了
if (CGRectContainsPoint(CGRectMake(frameX, frameY, wh, wh), point)) {
return btn;
}
}
return nil;
}
//设置Button被选中的状态
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
//当触摸开始的时候将之前的痕迹抹掉 重新开始
self.code = [[NSMutableString alloc]init];
self.isEnd = NO;
for (int i = 0; i < self.btns.count; i ++) {
UIButton *btn = self.btns[i];
btn.selected = NO;
}
[self.btns removeAllObjects];
//找到touch到的点的位置(此处只有一个点 就是开始的那个点)
CGPoint point = [self pointWithTouches:touches];
//判断这个点所在的Button
UIButton *btn = [self buttonWithPoint:point];
if (btn != nil && btn.selected == false) {
btn.selected = YES;
//把button加到数组中
[self.btns addObject:btn];
//并记录走过的路线 用Button的tag拼接出的字符串
[self.code appendString:[NSString stringWithFormat:@"%ld",(long)btn.tag]];
}
[self setNeedsDisplay];
}
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
//找到touch到的点的位置
CGPoint point = [self pointWithTouches:touches];
//判断这个点所在的Button
UIButton *btn = [self buttonWithPoint:point];
if (btn != nil && btn.selected == false) {
btn.selected = YES;
//把button加到数组中
[self.btns addObject:btn];
//并记录走过的路线 用Button的tag拼接出的字符串
[self.code appendString:[NSString stringWithFormat:@"%ld",(long)btn.tag]];
}
[self setNeedsDisplay];
}
//使用touchend清空数据
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
//绘制选中的按钮少于3个的时候没有轨迹记录
if (self.btns.count < 3) {
for (int i = 0; i < self.btns.count; i ++) {
UIButton *btn = self.btns[i];
btn.selected = NO;
}
[self.btns removeAllObjects];
}
else
{
//标志 结束
self.isEnd = YES;
}
[self setNeedsDisplay];
}
//优化 先判空
-(void)drawRect:(CGRect)rect
{
//如果没有选择的button 则不绘图
if (self.btns.count == 0) {
return;
}
//使用贝塞尔曲线绘制路线
UIBezierPath * path = [UIBezierPath bezierPath];
for (int i = 0; i < self.btns.count; i ++) {
UIButton *btn = self.btns[i];
if (i == 0) {
[path moveToPoint:btn.center];
}
else
{
[path addLineToPoint:btn.center];
}
}
//设置线的颜色
[[UIColor colorWithRed:23/255.0 green:171/255.0 blue:227/255.0 alpha:1] set];
//设置线的宽度
[path setLineWidth:3];
//设置连接风格
[path setLineJoinStyle:(kCGLineJoinRound)];
//判断是否结束 在touchEnd方法中更改isEnd的值
if (_isEnd == YES) {
if (![self.code isEqualToString:self.password]) {
//修改Path的颜色
[[UIColor redColor]set];
//发送通知 提醒ViewController更改Label上的文字
[[NSNotificationCenter defaultCenter] postNotificationName:@"changeLabel" object:nil];
}
else
{
//发送通知 提醒ViewController更改Label上的文字
[[NSNotificationCenter defaultCenter]postNotificationName:@"changeLabel2" object:nil];
}
}
//渲染
[path stroke];
}
@end使用方法
在ViewController的Xib里设计了界面,其中最下面正方形是关联SpeedDialView的View。
ViewController.m
<span style="font-size:18px;">@interface ViewController ()
@property (weak, nonatomic) IBOutlet UILabel *label;
@property (weak, nonatomic) IBOutlet SpeedDialView *speedDialView;
@end
@implementation ViewController
- (void)viewWillAppear:(BOOL)animated
{
self.label.text = @"请输入手势密码";
self.label.textColor = [UIColor darkGrayColor];
}
- (void)viewDidLoad {
[super viewDidLoad];
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(changeLabel) name:@"changeLabel" object:nil];
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(changeLabel2) name:@"changeLabel2" object:nil];
self.speedDialView.password = @"1345";
}
- (void)changeLabel
{
self.label.text = @"密码输入错误";
self.label.textColor = [UIColor redColor];
}
- (void)changeLabel2
{
self.label.text = @"恭喜,密码输入正确";
self.label.textColor = [UIColor greenColor];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
</span>最后,就是成果展示了~
大功告成~
我对明天没有期待,因为我对今天满意~
UIButton图片提供
最后,提供Demo地址点击打开链接
我是写的OC版的,感谢简书作者王鑫20111Swift版传送门的无私分享~
实践所写,如有错误,还请指正,谢谢!
这是我模仿的QQ手势解锁部分界面~
密码输入错误效果
密码输入正确效果
界面粗糙,还请海涵~
接下来开始上代码了~
我是自定义了一个SpeedDailView继承于UIView的九宫格界面
解释都在注释里了
SpeedDialView.h
#import <UIKit/UIKit.h>
@interface SpeedDialView : UIView
//用来盛放选中的button
@property (nonatomic,retain) NSMutableArray *btns;
//输入的密码
@property (nonatomic,strong) NSMutableString *code;
//正确密码
@property (nonatomic,strong) NSString *password;
//触摸是否结束
@property (nonatomic,assign) BOOL isEnd;
@end
SpeedDialView.m
#import "SpeedDialView.h"
@implementation SpeedDialView
- (instancetype)init
{
self = [super init];
if (self) {
}
return self;
}
//懒加载
- (NSMutableArray *)btns
{
if (!_btns) {
self.btns = [[NSMutableArray alloc]init];
}
return _btns;
}
//创建9个按钮
- (void)setUpBasicUI
{
for (int i = 0; i < 9; i++) {
UIButton *btn = [UIButton buttonWithType:(UIButtonTypeCustom)];
btn.tag = i;
[self addSubview:btn];
}
}
//设置9个按钮的位置
- (void)layoutSubviews
{
[super layoutSubviews];
//这个方法只运行一次
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[self setUpBasicUI];
});
//经典的9宫格算法
int totalColume = 3;
CGFloat bWidth = 74;
CGFloat bHeight = bWidth;
CGFloat margin = (self.frame.size.width - bWidth * totalColume)/(totalColume + 1);
for (int i = 0; i< self.subviews.count; i++) {
int currentRow = i/totalColume;
int currentColumn = i%totalColume;
CGFloat originX = margin + (currentColumn * (margin + bWidth));
CGFloat originY = currentRow * (margin + bHeight);
//设置Button的外观和大小
UIButton *btn = self.subviews[i];
[btn setImage:[UIImage imageNamed:@"xv"] forState:(UIControlStateNormal)];
[btn setImage:[UIImage imageNamed:@"shi"] forState:(UIControlStateSelected)];
btn.contentMode = UIViewContentModeCenter;
btn.userInteractionEnabled = false;
btn.frame = CGRectMake(originX, originY, bWidth, bHeight);
}
}
//获取当前的触摸点的坐标
- (CGPoint)pointWithTouches:(NSSet<UITouch *> *)touches
{
UITouch *touch = [touches anyObject];
CGPoint point = [touch locationInView:touch.view];
return point;
}
//判断当前点在不在Button中
- (UIButton *)buttonWithPoint:(CGPoint)point
{
for (int i = 0; i < self.subviews.count; i++) {
UIButton *btn = self.subviews[i];
CGFloat wh = btn.frame.size.width - 5;
//找到Button中心附近25*25的面积
CGFloat frameX = btn.center.x - wh * 0.5;
CGFloat frameY = btn.center.y - wh * 0.5;
//判断这个点在button中心附近25*25的面积内的话就是它了
if (CGRectContainsPoint(CGRectMake(frameX, frameY, wh, wh), point)) {
return btn;
}
}
return nil;
}
//设置Button被选中的状态
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
//当触摸开始的时候将之前的痕迹抹掉 重新开始
self.code = [[NSMutableString alloc]init];
self.isEnd = NO;
for (int i = 0; i < self.btns.count; i ++) {
UIButton *btn = self.btns[i];
btn.selected = NO;
}
[self.btns removeAllObjects];
//找到touch到的点的位置(此处只有一个点 就是开始的那个点)
CGPoint point = [self pointWithTouches:touches];
//判断这个点所在的Button
UIButton *btn = [self buttonWithPoint:point];
if (btn != nil && btn.selected == false) {
btn.selected = YES;
//把button加到数组中
[self.btns addObject:btn];
//并记录走过的路线 用Button的tag拼接出的字符串
[self.code appendString:[NSString stringWithFormat:@"%ld",(long)btn.tag]];
}
[self setNeedsDisplay];
}
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
//找到touch到的点的位置
CGPoint point = [self pointWithTouches:touches];
//判断这个点所在的Button
UIButton *btn = [self buttonWithPoint:point];
if (btn != nil && btn.selected == false) {
btn.selected = YES;
//把button加到数组中
[self.btns addObject:btn];
//并记录走过的路线 用Button的tag拼接出的字符串
[self.code appendString:[NSString stringWithFormat:@"%ld",(long)btn.tag]];
}
[self setNeedsDisplay];
}
//使用touchend清空数据
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
//绘制选中的按钮少于3个的时候没有轨迹记录
if (self.btns.count < 3) {
for (int i = 0; i < self.btns.count; i ++) {
UIButton *btn = self.btns[i];
btn.selected = NO;
}
[self.btns removeAllObjects];
}
else
{
//标志 结束
self.isEnd = YES;
}
[self setNeedsDisplay];
}
//优化 先判空
-(void)drawRect:(CGRect)rect
{
//如果没有选择的button 则不绘图
if (self.btns.count == 0) {
return;
}
//使用贝塞尔曲线绘制路线
UIBezierPath * path = [UIBezierPath bezierPath];
for (int i = 0; i < self.btns.count; i ++) {
UIButton *btn = self.btns[i];
if (i == 0) {
[path moveToPoint:btn.center];
}
else
{
[path addLineToPoint:btn.center];
}
}
//设置线的颜色
[[UIColor colorWithRed:23/255.0 green:171/255.0 blue:227/255.0 alpha:1] set];
//设置线的宽度
[path setLineWidth:3];
//设置连接风格
[path setLineJoinStyle:(kCGLineJoinRound)];
//判断是否结束 在touchEnd方法中更改isEnd的值
if (_isEnd == YES) {
if (![self.code isEqualToString:self.password]) {
//修改Path的颜色
[[UIColor redColor]set];
//发送通知 提醒ViewController更改Label上的文字
[[NSNotificationCenter defaultCenter] postNotificationName:@"changeLabel" object:nil];
}
else
{
//发送通知 提醒ViewController更改Label上的文字
[[NSNotificationCenter defaultCenter]postNotificationName:@"changeLabel2" object:nil];
}
}
//渲染
[path stroke];
}
@end使用方法
在ViewController的Xib里设计了界面,其中最下面正方形是关联SpeedDialView的View。
ViewController.m
<span style="font-size:18px;">@interface ViewController ()
@property (weak, nonatomic) IBOutlet UILabel *label;
@property (weak, nonatomic) IBOutlet SpeedDialView *speedDialView;
@end
@implementation ViewController
- (void)viewWillAppear:(BOOL)animated
{
self.label.text = @"请输入手势密码";
self.label.textColor = [UIColor darkGrayColor];
}
- (void)viewDidLoad {
[super viewDidLoad];
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(changeLabel) name:@"changeLabel" object:nil];
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(changeLabel2) name:@"changeLabel2" object:nil];
self.speedDialView.password = @"1345";
}
- (void)changeLabel
{
self.label.text = @"密码输入错误";
self.label.textColor = [UIColor redColor];
}
- (void)changeLabel2
{
self.label.text = @"恭喜,密码输入正确";
self.label.textColor = [UIColor greenColor];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
</span>最后,就是成果展示了~
大功告成~
我对明天没有期待,因为我对今天满意~
UIButton图片提供
最后,提供Demo地址点击打开链接
我是写的OC版的,感谢简书作者王鑫20111Swift版传送门的无私分享~
实践所写,如有错误,还请指正,谢谢!
相关文章推荐
- AJ学IOS(35)UI之Quartz2D仿真支付宝手势解锁_代理获得密码。
- 猫猫学IOS(三十五)UI之Quartz2D仿真支付宝手势解锁_代理获得密码。
- iOS开发Quartz2D之十二:手势解锁实例
- 手把手教你使用Quartz2D制作彩色涂鸦板和手势解锁
- (素材源码)猫猫学IOS(三十五)UI之Quartz2D仿真支付宝手势解锁_代理获得密码。
- iOS开发Quartz2D十二:手势解锁实例
- (素材源码)猫猫学IOS(三十五)UI之Quartz2D仿真支付宝手势解锁_代理获得密码。
- (素材源码)猫猫学IOS(三十五)UI之Quartz2D仿真支付宝手势解锁_代理获得密码。
- 猫猫学IOS(三十五)UI之Quartz2D仿真支付宝手势解锁_代理获得密码。
- iOS开发——UI进阶篇(十六)Quartz2D实战小例子
- iOS开发系列--Quartz 2D绘制2D图形和Core Image中强大的滤镜功能
- iOS 开发实战-锁屏界面(手势解锁)
- Quartz2D复习(二) --- 手势解锁
- Quartz 2D之手势解锁(支付宝)
- iOS - Quartz 2D 手势截屏绘制
- iOS开发系列--Quartz 2D绘制2D图形和Core Image中强大的滤镜功能
- 【ios系列】-Quartz 2D常用方法介绍
- UI进阶--Quartz2D和触摸事件的简单使用:手势解锁
- iOS 使用Quartz 2D画虚线 【转】
- [Web Chart系列之五] 3. 实战draw2d 之图形填充色(纯色 or 渐变)