OC图片滑动验证
没事逛cocoaChina的时候有人问图片验证码怎么做,我看了下,网上有很多第三方的框架,但好多都是收费的,所以考虑自己能否做一个,该封装有点简陋,不过可以根据自己需要自行修改
该代码用到的技术,UIBezierPath可以参考我的另外一篇博客、还UIProgressView的第二次封装、还有手势,这个我之前也有写过博客,和这个大同小异
效果图:

需要用到的代码:

CustomProgressView是对UIProgressView的封装,可以通过拖动滑块改变进度条value值,这个地方我用的是一个UILabel,有点难看,后期可以根据自己的需要改为图片,楼主的原则是'只要能用其他的控件代替,就不用图片'
CustomProgressView.h
#import <UIKit/UIKit.h> @interface CustomProgressView : UIView /** progress的value值 isEnd是否停止滑动 */ @property(nonatomic,copy)void(^blockProgressValue)(float value,BOOL isEnd); -(void)setProgress:(float)progress; @end
CustomProgressView.m
#import "CustomProgressView.h"
@interface CustomProgressView ()
@property(nonatomic,strong)UIProgressView *preView;
@property(nonatomic,strong)UILabel *trackLab;
@end
@implementation CustomProgressView
-(instancetype)initWithFrame:(CGRect)frame{
self = [super initWithFrame:frame];
if(self){
self.preView = [[UIProgressView alloc]initWithFrame:CGRectMake(0, frame.size.height/2.0, frame.size.width, 1)];
self.preView.progressTintColor = [UIColor redColor];
self.preView.trackTintColor = [UIColor grayColor];
[self addSubview:self.preView];
self.trackLab = [[UILabel alloc]initWithFrame:CGRectMake(0,frame.size.height/2.0-10, 20, 20)];
self.trackLab.backgroundColor = [UIColor redColor];
self.trackLab.userInteractionEnabled = YES;
[self addSubview:self.trackLab];
}
return self;
}
-(void)setProgress:(float)progress{
float x = self.bounds.size.width * progress;
CGRect rect = self.trackLab.frame;
rect.origin.x = x;
self.trackLab.frame = rect;
[self.preView setProgress:progress];
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
}
-(void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
UITouch *touch = [touches anyObject];
if([touch.view isKindOfClass:[UILabel class]]){
CGPoint point = [touch locationInView:[touch.view superview]];
float x = point.x;
CGRect rect = self.trackLab.frame;
if(x < 0 ){
rect.origin.x = 0;
self.trackLab.frame = rect;
return;
}
if(x > self.bounds.size.width-20){
rect.origin.x = self.bounds.size.width-20;
self.trackLab.frame = rect;
return;
}
rect.origin.x = x;
self.trackLab.frame = rect;
[self.preView setProgress:x/self.bounds.size.width];
if(self.blockProgressValue){
self.blockProgressValue(x/self.bounds.size.width,NO);
}
}
}
-(void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
UITouch *touch = [touches anyObject];
if([touch.view isKindOfClass:[UILabel class]]){
if(self.blockProgressValue){
self.blockProgressValue(self.preView.progress,YES);
}
}
}
@end
ImageLockView.h
#import <UIKit/UIKit.h> @interface ImageLockView : UIView -(void)show; -(void)hidden; @end
ImageLockView.m
#import "ImageLockView.h"
#import "CustomProgressView.h"
//屏幕的宽度
#define ScreenWidth [UIScreen mainScreen].bounds.size.width
//屏幕的高度
#define ScreenHeight [UIScreen mainScreen].bounds.size.height
//内容的宽度
#define ContentWidth 200
//内容的高度
#define ContentHeight 230
//间距
#define Margin 10
@interface ImageLockView (){
CGRect frontRect;//
}
/**半透明背景蒙版*/
@property(nonatomic,strong)UIView *backView;
/**内容view,白的的圆角矩形*/
@property(nonatomic,strong)UIView *contentView;
/**底下一层的Img*/
@property(nonatomic,strong)UIImageView *backImg;
/**滑动Img*/
@property(nonatomic,strong)UIImageView *frontImg;
/***最下方可以滑动的ProgressView*/
@property(nonatomic,strong)CustomProgressView *progressView;
@end
@implementation ImageLockView
- (instancetype)initWithFrame:(CGRect)frame{
frame = CGRectMake(0, 0, ScreenWidth, ScreenHeight);
self = [super initWithFrame:frame];
if(self){
self.backView = [[UIView alloc]initWithFrame:self.bounds];
self.backView.backgroundColor = [UIColor blackColor];
[self addSubview:self.backView];
self.contentView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, ContentWidth, ContentHeight)];
self.contentView.backgroundColor = [UIColor whiteColor];
self.contentView.layer.cornerRadius = 8.0f;
self.contentView.center = self.center;
[self addSubview:self.contentView];
self.backImg = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"WechatIMG"]];
self.frontImg = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"WechatIMG"]];
self.backImg.frame = CGRectMake(Margin, Margin, ContentWidth-Margin*2, ContentWidth-Margin*2);
self.frontImg.frame = CGRectMake(Margin, Margin, ContentWidth-Margin*2, ContentWidth-Margin*2);
[self.contentView addSubview:self.backImg];
[self.contentView addSubview:self.frontImg];
self.progressView = [[CustomProgressView alloc]initWithFrame:CGRectMake(Margin, CGRectGetMaxY(self.backImg.frame)+Margin, ContentWidth-Margin*2, Margin*2)];
[self.contentView addSubview:self.progressView];
__block typeof(self)weakSelf = self;
self.progressView.blockProgressValue = ^(float value,BOOL isEnd) {
if(isEnd){
//这个地方判断5只是为了给滑动的图片一个容错性,偏离5个像素也判断是对的
CGRect frontRect = weakSelf.frontImg.frame;
CGRect backRect = weakSelf.backImg.frame;
if(frontRect.origin.x-backRect.origin.x < 5 && frontRect.origin.x-backRect.origin.x > -5){
//成功了移除
[weakSelf hidden];
}else{
//失败了刷新继续拼图
[weakSelf refreshView];
}
}else{
float width = frame.size.width * value;
CGRect rect = weakSelf.frontImg.frame;
rect.origin.x = self->frontRect.origin.x+width;
weakSelf.frontImg.frame = rect;
}
};
[self refreshView];
}
return self;
}
/**
刷新当前界面
*/
-(void)refreshView{
//刷新的时候progressView的值为0,设置到原始值
[self.progressView setProgress:0];
//如果self.backImg上有上次停留的Layer,则删除
for(CALayer *layer in [self.backImg.layer sublayers]){
[layer removeFromSuperlayer];
}
int width = self.backImg.frame.size.width - 40;
//x-50的原因以及height-40是不想让模块出现在边框之外
int x = arc4random() % width ;
if(x < 50){
x = 50;
}
int height = self.backImg.frame.size.height - 40;
int y = arc4random() % height;
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
shapeLayer.path = [self getPath].CGPath;
[shapeLayer setFillColor:[UIColor whiteColor].CGColor];
shapeLayer.frame = CGRectMake(x, y, 36, 36);
[self.backImg.layer addSublayer:shapeLayer];
//-x+Margin是因为backImg前面有Margin个空白间距
frontRect = CGRectMake(-x+Margin, self.backImg.frame.origin.y, self.backImg.frame.size.width, self.backImg.frame.size.height);
self.frontImg.frame = frontRect;
UIBezierPath *path = [self getPath];
CGAffineTransform transform = CGAffineTransformMakeTranslation(x, y);
[path applyTransform: transform];
CAShapeLayer *maskLayer = [CAShapeLayer layer];
maskLayer.path = path.CGPath;
self.frontImg.layer.mask = maskLayer;
}
-(void)show{
UIWindow *window = [[UIApplication sharedApplication]keyWindow];
[window addSubview:self];
__block typeof(self)weakSelf = self;
[UIView animateWithDuration:.5f animations:^{
weakSelf.backView.alpha = .3f;
}];
}
-(void)hidden{
__block typeof(self)weakSelf = self;
[UIView animateWithDuration:.5f animations:^{
CGRect rect = weakSelf.frame;
rect.size.height = 0;
weakSelf.frame = rect;
weakSelf.alpha = 0;
} completion:^(BOOL finished) {
[weakSelf removeFromSuperview];
}];
}
//画蒙版的形状
-(UIBezierPath *)getPath{
UIBezierPath * path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(0.f, 4.0f)];
[path addLineToPoint:CGPointMake(12.f, 4.0f)];
[path addArcWithCenter:CGPointMake(16.f,4.0f) radius:4.0 startAngle:M_PI endAngle:2*M_PI clockwise:YES];
[path addLineToPoint:CGPointMake(32.f, 4.0f)];
[path addLineToPoint:CGPointMake(32.f, 12.f)];
[path addArcWithCenter:CGPointMake(32.f,20.f) radius:4.0 startAngle:1.5*M_PI endAngle:2.5*M_PI clockwise:YES];
[path addLineToPoint:CGPointMake(32.f, 36.f)];
[path addLineToPoint:CGPointMake(24.f, 36.f)];
[path addArcWithCenter:CGPointMake(16.f,36.f) radius:4.0 startAngle:2*M_PI endAngle:M_PI clockwise:NO];
[path addLineToPoint:CGPointMake(0.f, 36.f)];
[path addLineToPoint:CGPointMake(0.f, 28.f)];
[path addArcWithCenter:CGPointMake(0.f,20.f) radius:4.0 startAngle:2.5*M_PI endAngle:1.5*M_PI clockwise:NO];
[path closePath];
return path;
}
@end
使用

浙公网安备 33010602011771号