iOS滑块拼图验证

滑动拼图.png

实现过程

  1. 初始化UI
[self addSubview:({//背景图片
        self.imageViewBG.frame = CGRectMake(margin, CGRectGetMaxY(self.tipLabel.frame)+margin, self.width-margin*2, imageHeight);
        self.imageViewBG.contentMode =  UIViewContentModeScaleAspectFill;
        self.imageViewBG.clipsToBounds = YES;
        self.imageViewBG;
    })];

//添加右侧遮罩层,并绘制路径
 UIBezierPath *path = getCodePath();
    
    [self.imageViewBG addSubview:({
        self.maskView.frame = CGRectMake(self.randomPoint.x, self.randomPoint.y, codeSize, codeSize);
        
        self.maskLayer.frame = CGRectMake(0, 0, codeSize, codeSize);
        self.maskLayer.path = path.CGPath;
        self.maskLayer.strokeColor = [UIColor whiteColor].CGColor;
        [self.maskView.layer addSublayer:self.maskLayer];
        
        self.maskView;
    })];

//添加左侧可滑动图片,并绘制路径
UIImage * thumbImage = [self.imageViewBG.image dw_SubImageWithRect:self.maskView.frame];
    thumbImage = [thumbImage dw_ClipImageWithPath:path mode:(DWContentModeScaleToFill)];
    [self.imageViewBG addSubview:({
        self.moveImage.frame = CGRectMake(0, self.randomPoint.y-offset, codeSize+offset, codeSize+offset);
        self.moveImage.image = thumbImage;
        self.moveImage;
    })];

[self addSubview:({//滑杆
        self.slider.frame = CGRectMake(margin, CGRectGetMaxY(self.imageViewBG.frame) + margin, self.width-margin*2, 30);
        [self.slider addTarget:self action:@selector(buttonAction:forEvent:) forControlEvents:UIControlEventAllTouchEvents];
        self.slider.minimumTrackTintColor = [UIColor colorWithRed:247/256.0 green:63/256.0 blue:94/256.0 alpha:1.0];
        self.slider.maximumTrackTintColor = [UIColor colorWithRed:251/256.0 green:88/256.0 blue:96/256.0 alpha:1.0];
        UIImage *tempImage = [UIImage imageNamed:@"SliderImage"];
        tempImage = [tempImage imageScaleToSize:CGSizeMake(30, 30)];
        [self.slider setThumbImage:tempImage forState:UIControlStateNormal];
        [self.slider setThumbImage:tempImage forState:UIControlStateHighlighted];
        self.slider;
    })];

绘制滑块贝塞尔曲线

static inline UIBezierPath* getCodePath() {
    UIBezierPath *path = [UIBezierPath bezierPath];
    [path moveToPoint:CGPointMake(0, 0)];
    [path addLineToPoint:CGPointMake(codeSize*0.5-offset,0)];
    [path addQuadCurveToPoint:CGPointMake(codeSize*0.5+offset, 0) controlPoint:CGPointMake(codeSize*0.5, -offset*2)];
    [path addLineToPoint:CGPointMake(codeSize, 0)];
   
    [path addLineToPoint:CGPointMake(codeSize,codeSize*0.5-offset)];
    [path addQuadCurveToPoint:CGPointMake(codeSize, codeSize*0.5+offset) controlPoint:CGPointMake(codeSize+offset*2, codeSize*0.5)];
    [path addLineToPoint:CGPointMake(codeSize, codeSize)];
    
    [path addLineToPoint:CGPointMake(codeSize*0.5+offset,codeSize)];
    [path addQuadCurveToPoint:CGPointMake(codeSize*0.5-offset, codeSize) controlPoint:CGPointMake(codeSize*0.5, codeSize-offset*2)];
    [path addLineToPoint:CGPointMake(0, codeSize)];
    
    [path addLineToPoint:CGPointMake(0,codeSize*0.5+offset)];
    [path addQuadCurveToPoint:CGPointMake(0, codeSize*0.5-offset) controlPoint:CGPointMake(0+offset*2, codeSize*0.5)];
    [path addLineToPoint:CGPointMake(0, 0)];
    
    [path stroke];
    return path;
}

监听滑竿滑动并改变左侧可移动图片的frame

- (void)buttonAction:(UISlider*)slider forEvent:(UIEvent *)event{
    UITouchPhase phase = event.allTouches.anyObject.phase;
    if (phase == UITouchPhaseBegan) {
        dispatch_queue_t global = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
        self.seconds = 0;
        timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, global);
        dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 0.1 * NSEC_PER_SEC, 0 * NSEC_PER_SEC);
        dispatch_source_set_event_handler(timer, ^{
            self.seconds+=0.1;
            NSLog(@"%.1f",self.seconds);
        });
        dispatch_resume(timer);
    }
    else if(phase == UITouchPhaseEnded){
        if (timer) {
            dispatch_source_cancel(timer);
        }
        
        CGFloat x = self.maskView.frame.origin.x;
        if (fabs(self.moveImage.frame.origin.x-x)<=5.00) {
            [self.layer addAnimation:successAnimal() forKey:@"successAnimal"];
            [self showToast:YES];
        }else{
            [self.layer addAnimation:failAnimal() forKey:@"failAnimal"];
            [self defaultSlider];
            [self showToast:NO];
        }
    }else if (phase == UITouchPhaseMoved){
        if (slider.value>self.width-margin*2-codeSize) {
            slider.value = self.width-margin*2-codeSize;
            return;
        }
        [self changeMoveImageFrameWithVlue:slider.value];
        
    }
}

//设置默认的滑动
- (void)defaultSlider{
    self.slider.value = 0;
    [self changeMoveImageFrameWithVlue:self.slider.value];
}

//图片位置随着Slider滑动改变frame
- (void)changeMoveImageFrameWithVlue:(CGFloat)value{
    CGRect rect = self.moveImage.frame;
    CGFloat x = value * (self.imageViewBG.frame.size.width)-(value*codeSize);
    rect.origin.x = x;
    self.moveImage.frame = rect;
}

成功和失败的动画及提示

//成功动画
static inline CABasicAnimation *successAnimal(){
    CABasicAnimation * animation = [CABasicAnimation animationWithKeyPath:@"opacity"];
    animation.duration = 0.2;
    animation.autoreverses = YES;
    animation.fromValue = @1;
    animation.toValue = @0;
    animation.removedOnCompletion = YES;
    return animation;
}

//失败动画
static inline CABasicAnimation *failAnimal(){
    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
    [animation setDuration:0.08];
    animation.fromValue = @(-M_1_PI/16);
    animation.toValue = @(M_1_PI/16);
    animation.repeatCount = 2;
    animation.autoreverses = YES;
    return animation;
}

//成功的操作
- (void)showToast:(BOOL)success {
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        __weak WMZCodeView *codeView = self;
        NSString *tip = @"";
        if (self.seconds>0) {
            tip = [NSString stringWithFormat:@"耗时%.1fs",self.seconds];
        }
        UIAlertController *alert = [UIAlertController alertControllerWithTitle:success ? @"验证成功" : @"验证失败" message:tip preferredStyle:UIAlertControllerStyleAlert];
        UIAlertAction *action = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
            if (codeView.block) {
                codeView.block(success);
            }
            [codeView refreshAction];
        }];
        [alert addAction:action];
        [[self getCurrentVC] presentViewController:alert animated:YES completion:nil];
    });
   
}

http://code.cocoachina.com/view/137862
https://www.jianshu.com/p/93d83018e5cd
https://github.com/AlbertXYZ/PuzzleVerify
https://github.com/wsl2ls/YanZhengCode
https://www.jianshu.com/p/a7021d87864b
https://github.com/zekunyan/TTGPuzzleVerify
https://github.com/kang558/eros-plugin-ios-TencentCaptcha
自定义滑杆样式

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,711评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,079评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,194评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,089评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,197评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,306评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,338评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,119评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,541评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,846评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,014评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,694评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,322评论 3 318
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,026评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,257评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,863评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,895评论 2 351

推荐阅读更多精彩内容

  • 不知不觉2017年的余额已经所剩无几了 下面是我这一年来收藏的关于IOS开发的一些知识点 . iOS功能 iOS ...
    临渊还在阅读 674评论 0 0
  • 昨天参加雅集成长营的周检视,晓萍问了一个之前从没想过的问题:“假如有一天你不幸离开了,你会为你的孩子招...
    自然之美0608阅读 307评论 0 0
  • 听说他出家了 他二十年前做艺术评论 现在做了方丈 经常给人摸顶 他住在山上 孩子和孩子的妈 住在山下 我没问那是哪...
    灰鸟张学海阅读 492评论 1 0
  • 从前两年,机缘巧合下接触了茶叶,就爱上了。对于茶最初的印象是家里大人们总爱泡一口浓浓的绿茶,自己尝一口,重重的苦涩...
    星星醒了阅读 248评论 0 2
  • 时值六一儿童节,许多人纷纷怀念自己曾经的岁月,成龙大哥也不例外,放出多张老照片,包含他的父母、妻子林凤娇以及七小福...
    电影聚焦阅读 500评论 0 2