美文网首页其它技术点在iOS开发的道路上越走越远iOS分享世界
老司机出品———疯狂造轮子之滑动验证码

老司机出品———疯狂造轮子之滑动验证码

作者: 老司机Wicky | 来源:发表于2017-04-18 14:20 被阅读1212次
滑动验证码

消失了好久,大家放心,我还活着。
要问我为什么消失了这么久,如果你知道什么叫封闭开发或许你会懂我。


笑不出来

然而最近一直也没时间搞什么飞机,也没有什么能拿出来跟大家分享的,就把最近开发过程中写的一些小东西贴出来给大家看吧。
因为东西比较少,而且没有什么新鲜的技术点,所以老司机先把效果图放出来,这样的话如果你不感兴趣可能看到这就够了。

当前支持Cocoapods的库

老司机这里还是主推DWCoreTextLabel,他是一个基于CoreText的异步绘制的图文混排控件,并且支持图片的异步加载与缓存,基本上可以完美的实现图文混排需求。你值得使用。

DWCheckBox就是单选复选框了,也是一个快捷使用并且有着高定制型的类库。


继承UIControl重新实现一个Slider

广告打完了咱们来看第二环节,slider。
最初的时候其实我就是想实现后面那个步进Slider,最初的想法继承UISlider去重写,奈何转了一大圈,各种私有属性用一遍也无法完美的完成我的需求。

主要是由于UISlider中对于滑块和滑竿的定制性很困难,所以自己重写一个Slider吧。

所以为什么想到继承自UIControl去写呢?第一是UISlider继承自UIControl,第二是UIControl封装了-addTarget:selector:events以及事件追踪的一系列方法。

其实UIControl有四个核心的方法,是用于控制事件追踪的。

///判断是否开始事件追踪
-(BOOL)beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event;
///判断事件追踪是否继续
-(BOOL)continueTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event;
///事件追踪取消时处理
-(void)cancelTrackingWithEvent:(UIEvent *)event;
///事件追踪结束时处理
-(void)endTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event;

使用方法无非就是判断当视图接收到事件是如何追踪,可以看一下老司机写Slider的处理。

#pragma mark --- tracking Method ---
-(BOOL)beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event {
    CGPoint location = [touch locationInView:self];
    location = [self.thumbLayer convertPoint:location fromLayer:self.layer];
    if ([PathWithBounds(self.thumbLayer.bounds, FitCornerRadius(self.thumbLayer, self.thumbCornerRadius)) containsPoint:location]) {
        self.clickOnThumb = YES;
        return YES;
    }
    location = [self.trackBgLayer convertPoint:location fromLayer:self.thumbLayer];
    if ([PathWithBounds(self.trackBgLayer.bounds, FitCornerRadius(self.trackBgLayer, self.trackCornerRadius)) containsPoint:location]) {
        self.clickOnThumb = NO;
        return YES;
    }
    return NO;
}

-(BOOL)continueTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event {
    CGPoint location = [touch locationInView:self];
    CGFloat margin = FitMarginForThumb(self.thumbSize, [self thumbMarginForBounds:self.bounds]);
    location.x -= margin;
    CGFloat actualW = CGRectGetWidth([self trackRectForBounds:self.bounds]) - margin * 2;
    if (location.x < 0) {
        location.x = 0;
    } else if (location.x > actualW) {
        location.x = actualW;
    }
    CGFloat percent = location.x / actualW;
    CGFloat value = self.minimumValue + (self.maximumValue - self.minimumValue) * percent;
    if (value == self.value) {
        return YES;
    }
    _value = value;
    [self sendActionsForControlEvents:UIControlEventValueChanged];
    if (self.clickOnThumb) {
        [self updateValueAnimated:NO];
        return YES;
    } else {
        [self updateValueAnimated:YES];
        self.clickOnThumb = NO;
        return NO;
    }
}

-(void)cancelTrackingWithEvent:(UIEvent *)event {
    self.clickOnThumb = NO;
}

-(void)endTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event {
    self.clickOnThumb = NO;
}

处理过事件追踪,我们只要处理好视图相关的内容即可。

此处可以分为两种思路,一种是通过DrawRect方法去追踪行为后不断绘制,另一种是通过Layer展示各个图层并追踪行为。这里呢,老司机更加推荐使用Layer去处理图层,因为本身DrawRect方法中的代码是使用CPU进行预算然后将bitmap提交给GPU,他处理绘制的速度远不如CALayer直接使用GPU来的快。

图层的绘制老司机在CoreAnimation系列中已经写得很细了,在这也就不多写了。
老司机重写的DWSlider是一个UISlider的替换类,它具备UISlider的所有功能,并且还能自由定制你的Slider的各个属性,相比UISlider来讲可玩性更强,老司机这里放一个传送门


步进Slider

DWStepSlider是一个分段的Slider,继承自DWSlider。
主要是实现分段的Slider至实现,主要思想还是通过更改事件追踪后的赋值。

#pragma mark --- tracking Method ---
-(BOOL)beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event {
    CGPoint location = [touch locationInView:self];
    location = [self.thumbLayer convertPoint:location fromLayer:self.layer];
    if ([PathWithBounds(self.thumbLayer.bounds, FitCornerRadius(self.thumbLayer, self.thumbCornerRadius)) containsPoint:location]) {
        self.clickOnThumb = YES;
        return YES;
    }
    location = [self.trackBgLayer convertPoint:location fromLayer:self.thumbLayer];
    if ([PathWithBounds(self.trackBgLayer.bounds, FitCornerRadius(self.trackBgLayer, self.trackCornerRadius)) containsPoint:location]) {
        self.clickOnThumb = NO;
        return YES;
    }
    return NO;
}

-(BOOL)continueTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event {
    CGPoint location = [touch locationInView:self];
    CGFloat margin = FitMarginForThumb(self.thumbSize, [self thumbMarginForBounds:self.bounds]);
    location.x -= margin;
    CGFloat actualW = CGRectGetWidth([self trackRectForBounds:self.bounds]) - margin * 2;
    if (location.x < 0) {
        location.x = 0;
    } else if (location.x > actualW) {
        location.x = actualW;
    }
    CGFloat percent = location.x / actualW;
    CGFloat value = self.minimumValue + (self.maximumValue - self.minimumValue) * percent;
    if (value == self.value) {
        return YES;
    }
    [self setValue:value updateThumb:NO];
    [self sendActionsForControlEvents:UIControlEventValueChanged];
    if (self.clickOnThumb) {
        [self updateValueAnimated:NO];
        return YES;
    } else {
        [self setValue:FixValue(value, _nodes.count) updateThumb:NO];
        [self updateValueAnimated:YES];
        return NO;
    }
}

-(void)cancelTrackingWithEvent:(UIEvent *)event {
    if (self.clickOnThumb) {
        self.value = FixValue(self.value, _nodes.count);
        self.clickOnThumb = NO;
    }
}

-(void)endTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event {
    if (self.clickOnThumb) {
        self.value = FixValue(self.value, _nodes.count);
        self.clickOnThumb = NO;
    }
}

至于图形还是CAShapeLayer的各种形状,老司机也早就说过了,还是传送门吧。


好吧,今天其实也没什么新鲜内容,毕竟都是一些UI控件的封装。
不过也是捋一下思路,控件要如何封装,所以还是不要脸的发出来了。
喜欢哪个给哪个Star恩,就是这么好意思

图文无关

相关文章

网友评论

  • 7f59d79bfd8b:你好,这篇文章给了我很大的帮助,我对使用KVO对slider的状态监控进行仿写时,发现在8.0的真机系统运行时,if ([change[@"new"] integerValue] == 0 && [change[@"old"] integerValue] == 1) ///silder结束拖动,开始验证
    这个状态是不显示的。目前只遇到在8.0上的问题,请问可以给一些思路上的修改建议吗?
  • 大魔导师刘秀:正需要用到这个,非常感谢!
  • GavinKang:老司机,你那个对截取图片,是根据图片的像素截 rect 的吧,不是根据视图的 rect 截取的,有没有根据视图rect截取,和图片像素没关系的
    老司机Wicky:@iOS开发的毛毛虫 放大后按比例计算一下目标尺寸
    GavinKang:@老司机Wicky 例如QQ的更换头像:不管图片放大多少倍,只截显示在圆内的图片,怎么实现
    老司机Wicky:@iOS开发的毛毛虫 根据rect不是还要用到图片的原始尺寸。那你用钻石尺寸与目标尺寸做个比例再用我提供的api不是一样
  • devRen:老司机带带我,能把UISlider控件弄成弧形或圆形的吗
    老司机Wicky:@devRen 集成uicontrol重写一个吧
  • 老马的春天:老司机,可否写点详细介绍runloop的文章呢?
    老司机Wicky:@老马的春天 提上行程
  • Fooler:老司机,可否写个,异步上传多张图片的文章呀,或者给我个思路也行,最重要的是上传速度快一点
  • 邢泽:很久没造轮子了
  • 春泥Fu:天上一天,地上一年,老夫等了你几十年,你终于出现了。。。
  • NSScorpio:(滴,老年卡👴)好久没发车了

本文标题:老司机出品———疯狂造轮子之滑动验证码

本文链接:https://www.haomeiwen.com/subject/nzyxzttx.html