之前写了一篇关于锁屏的文章,是密码锁屏,可以参照:
该篇是要讲解如何开发手势解锁,完整代码在github上。
关于如何在App后台启动等问题,该篇就不再赘述,之专注于介绍核心的实现部分。源代码在Github上可以获取。
实现思路
手势锁屏是一个3*3的9宫格界面,将每一个宫格用一个Button表示,然后给每一个button附上一个tag,捕捉touch事件,通过判断手势划过哪些button,纪录下tag数值,作为密码。
变量定义
手势锁屏是定义在GuestureView的UIView类中。主要的UI和事件响应都在这个类中完成。
[code]
@interface GuestureView()
@property (nonatomic,strong) NSMutableArray * buttonsArray;
@property (nonatomic,assign) CGPoint currentPoi;
定义两个变量:
buttonsArray:用来记录划过哪些Button
currentPoi用:来记录当前手指所在的point
UI布局
定义9个UIButton控件
[code]
-(id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self configButtons];
}
return self;
}
-(void)configButtons
{
self.buttonsArray = [NSMutableArray array];
for (int i = 0 ; i < 9 ; ++i) {
UIButton * btn = [UIButton buttonWithType:UIButtonTypeCustom];
btn.tag = i;
btn.userInteractionEnabled = NO;
[self addSubview:btn];
[btn setBackgroundImage:[UIImage imageNamed:@"lock"] forState:UIControlStateNormal];
[btn setBackgroundImage:[UIImage imageNamed:@"unlock"] forState:UIControlStateSelected];
}
}
-(void)layoutSubviews
{
[super layoutSubviews];
for(int i = 0 ; i < [self.subviews count] ; ++i) {
UIButton *btn=self.subviews[i];
CGFloat row = i/3;
CGFloat loc = i%3;
CGFloat btnW=74;
CGFloat btnH=74;
CGFloat padding=(self.frame.size.width-3*btnW)/4;
CGFloat btnX=padding+(btnW+padding)*loc;
CGFloat btnY=padding+(btnW+padding)*row;
btn.frame=CGRectMake(btnX, btnY, btnW, btnH);
}
//密码提示Label
UILabel * passwordLabel = [[UILabel alloc] init];
passwordLabel.text = @"密码是:L";
passwordLabel.textColor = [UIColor grayColor];
[passwordLabel sizeToFit];
[self addSubview:passwordLabel];
passwordLabel.translatesAutoresizingMaskIntoConstraints = NO;
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-400-[passwordLabel]"
options:0
metrics:nil
views:NSDictionaryOfVariableBindings(passwordLabel)]];
}
每个Button都赋给一个tag,且userInteractionEnabled为NO。
Button的frame在layoutSubviews里设置。
手势响应
主要实现三个touch事件:
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
这三个事件是手势解锁的核心代码。
[code]
#pragma mark - touch event
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
CGPoint startPoint = [self getCurrentPoint:touches];
UIButton * btn = [self getButtonWithCurrentPoint:startPoint];
if (btn && btn.selected != YES) {
btn.selected = YES;
[self.buttonsArray addObject:btn];
}
self.currentPoi = startPoint;
[self setNeedsDisplay];
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
CGPoint point = [self getCurrentPoint:touches];
UIButton * btn = [self getButtonWithCurrentPoint:point];
if (btn && btn.selected != YES) {
btn.selected = YES;
[self.buttonsArray addObject:btn];
}
[self setNeedsDisplay];
self.currentPoi = point;
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
NSMutableString * passWordString = [[NSMutableString alloc] init];
for (UIButton * btn in self.buttonsArray) {
[passWordString appendFormat:@"%ld", (long)btn.tag];
}
NSLog(@"password is %@",passWordString);
[self.buttonsArray makeObjectsPerformSelector:@selector(setSelected:) withObject:@NO];
[self.buttonsArray removeAllObjects];
[self setNeedsDisplay];
self.currentPoi = CGPointZero;
if ([self.delegate respondsToSelector:@selector(unlockFromGuesture:)]) {
if ([passWordString isEqualToString:@"03678"])
{
[self.delegate unlockFromGuesture:YES];
}
else
{
[self.delegate unlockFromGuesture:NO];
}
}
}
其中touchedEnded中调用了一个delegate方法,这个方法是为通知superView密码是否正确,然后交给superview来处理。
代码中涉及到两个方法:
//获得当前手指所在point
-(CGPoint)getCurrentPoint:(NSSet *)touches
//获得该点所在的Button。
-(UIButton *)getButtonWithCurrentPoint:(CGPoint)point
[code]
#pragma mark - point event
-(CGPoint)getCurrentPoint:(NSSet *)touches
{
UITouch * touch = [touches anyObject];
CGPoint point = [touch locationInView:touch.view];
return point;
}
-(UIButton *)getButtonWithCurrentPoint:(CGPoint)point
{
for (UIButton * btn in self.subviews) {
if (CGRectContainsPoint(btn.frame, point)) {
return btn;
}
}
return nil;
}
绘图
用Core Graphic实现划线效果。
[code]
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextClearRect(context, rect);
for (int i = 0; i < self.buttonsArray.count; ++i) {
UIButton * btn = self.buttonsArray[i];
if (0 == i)
{
CGContextMoveToPoint(context, btn.center.x, btn.center.y);
}
else
{
CGContextAddLineToPoint(context, btn.center.x,btn.center.y);
}
}
if (self.buttonsArray.count > 0) {
CGContextAddLineToPoint(context, self.currentPoi.x, self.currentPoi.y);
}
CGContextSetLineWidth(context, 10);
CGContextSetLineJoin(context, kCGLineJoinRound);
CGContextSetLineCap(context, kCGLineCapRound);
CGContextSetRGBStrokeColor(context, 20/255.0, 107/255.0, 153/255.0, 1);
CGContextStrokePath(context);
CGContextSaveGState(context);
CGContextRestoreGState(context);
}
该实现放在drawRect方法中,每当调用setNeedsDisplay方法是都会执行drawRect。
如果有任何问题欢迎再下面留言,或者扫描二维码
