iOS 開發實戰-鎖屏介面(手勢解鎖)
阿新 • • 發佈:2018-12-31
之前寫了一篇關於鎖屏的文章,是密碼鎖屏,可以參照:
關於如何在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。
如果有任何問題歡迎再下面留言,或者掃描二維碼