没事逛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
使用