The old driver – – the wheel made of the slide code

The old driver - - the wheel made of the slide code
sliding verification code

Disappeared for a long time, we rest assured that I am still alive.
ask me why I’ve been gone so long, if you know what it means to be closed, maybe you’ll understand me.

The old driver - - the wheel made of the slide code
can’t smile

recently, however, there is no time to engage in any aircraft, there is nothing to be able to come up with to share with you, the recent development of the process to write some small things posted to everyone to see it.
because things are relatively small, and there is no new technical point, so the old driver first put out the renderings, so if you are not interested in this may be enough to see.

The old driver - - the wheel made of the slide code
slider validation view, I jump to the warehouse yo
The old driver - - the wheel made of the slide code
step slider, I jumped into the warehouse.

In this article, you will see the following:

  • Slide validation view
  • Inheriting UIControl to implement a Slider
  • Step Slider

Slide validation view

See this and believe that you might be interested in this slide verification. The reason why the
write this control, because the need to use, but there is no corresponding class library can be used directly.

All effects are modeled on the effects of the daily web pages, so we should first analyze what we need.

  • First of all, we need a map
  • Second, we should base on the interception from a small part as a slider
  • Finally, the slider position should be changed to verify the success of the final location of the intercept

Demand in this, it may be the only technical point is how to intercept the picture.

#pragma mark - the interception of the current image image object in the rect region (UIImage *) - dw_SubImageWithRect: (CGRect rect) {/ / / prevent handled image scale 1 rect scale CGRect error CGFloat = self.scale; scaleRect = CGRectMake (rect.origin.x * scale, rect.origin.y * scale, rect.size.width * scale, rect.size.height * scale; CGImageRef) newImageRef = CGImageCreateWithImageInRect (self.CGImage, scaleRect); UIImage *newImage = [[UIImage imageWithCGImage:newImageRef] dw_RescaleImageToSize: rect.size]; CGImageRelease (newImageRef); return newImage;} #pragma mark compression image to the specified size (UIImage *) - dw_RescaleImageToSize: (CGSize size) {CGRect = Rect (CGRect) {CGPointZero, size}; UIGraphicsBeginImageContextWithOp Tions (size, NO, [UIScreen, mainScreen].scale); [self drawInRect:rect]; UIImage *resImage = UIGraphicsGetImageFromCurrentImageContext (UIGraphicsEndImageContext); (return); resImage;}

The code is written by an old driver in a UIImage category, so you should know that all self are a UIImage instance. Well, in this category, the old driver encapsulates a lot of UIImage commonly used methods, as follows:

High performance according to the name of image retrieval is changing the local picture + (UIImage *) dw_ImageNamed: (NSString * name); / / / high performance return without delay immediately decompressed picture examples + (UIImage *) dw_ImageWithUrl: (NSURL * URL); / / / convert images into Base64 string - (NSString *) dw_ImageToBase64String; ///Base64 (UIImage + into pictures * (NSString * base64String) dw_ImageWithBase64String:); / / / take pictures of a point color (UIColor *) dw_ColorAtPoint: point (CGPoint); / / / according to the given color layer picture + (UIImage *) dw_ImageWithColor: (UIColor * color); / / / on the gray space generation picture (UIImage *) dw_ConvertToGrayImage; / / / generate the color picture the object dw_ConvertToReversedColor (UIImage *); / / / with the given color image silhouette - (UIImage) dw_ConvertToSketchWithColor: (UIColor * color); / / / generation process Each pixel color of the picture (UIImage *) (dw_ConvertImageWithPixelHandler: (void ^) (UInt8 * pixel, int x, int y handler)); / / / get rounded picture (UIImage *) dw_CornerRadius: (CGFloat) radius withWidth: (CGFloat) width contentMode: mode (DWContentMode); / / / path according to the given crop the picture - (UIImage *) dw_ClipImageWithPath: (* UIBezierPath) path mode: mode (DWContentMode); / / / get the rotation angle of the picture (UIImage *) dw_RotateImageWithAngle: angle (CGFloat); / / / according to the given direction of rotation picture - (UIImage*) dw_RotateWithOrient: (UIImageOrientation) orient; / / / vertical flip - (UIImage * dw_FlipVertical; / / / level) flip - (UIImage *) dw_FlipHorizontal compressed images to the specified size; / / / - (UIImage *) dw_RescaleImageToSize: size (CGSize); / / / compressed picture to the designated pixel (UIImage * dw_) RescaleImageToPX: (CGFloat toPX); / / / correct direction of picture - (UIImage *) dw_FixOrientation image rect; / / / the interception of the current image object region - (UIImage *) dw_SubImageWithRect: Rect (CGRect); / / / create a tile in the specified size inside the picture - (UIImage) dw_GetTiledImageWithSize: (CGSize) ///UIView into size; UIImage + (UIImage *) dw_ImageFromView: (UIView * view); / / / two images to generate a picture + (UIImage*) dw_MergeImage: (UIImage*) firstImage withImage: (UIImage*) secondImage;

This classification is still relatively full, the old driver is more recommended, to a portal, feel good, then give me a star bar.

So with the help of this category, you should be able to capture a portion of the picture from the whole picture:

  • Generate an area at random to define it as a verification area and cover the white translucent cover of the slider in the area
  • Create a Layer with the same shape as the above area, and the good image is given to the Layer, and the Bessel curve is used to draw the Layer into the shape of the slider
  • Finally, when the position of the validation view slider is changed to the verification area, the verification is successful.

Idea is relatively simple, it is relatively simple to achieve, more than and 300 lines of code, the old driver put all the code directly:

- (instancetype) initWithFrame: (CGRect) {NSAssert (frame (frame.size.width > = 100; & & frame.size.height = > 40), "To get a better @ experience, you may set the width more than 100 and height more than 50"); if (self = [super initWithFrame:frame]) {_useRandomValue = YES; _targetValue = DWSlideCaptchaUndefineValue; _thumbCenterY = DWSlideCaptchaUndefineValue; _tolerance = DWSlideCaptchaUndefineValue; _thumbSize = puzzlePath (.Bounds.size return self);};} - (instancetype) initWithFrame: (CGRect) frame bgImage: (UIImage * bgImage) {if (self = [self initWithFrame:frame]) {[self = beginConfiguration]; self.bgImage bgImage; [self commitConfiguration];} Return self (void);} - beginConfiguration {_configurating = YES; self.resetTargetPoint = YES;} - {(void) commitConfiguration if (! Self.configurating) {return}; _configurating = NO; self.layer.contents = (ID) self.bgImage.CGImage; [self handlePositionLayer]; [self handleThumbLayer]; [self hideThumbWithAnimated:NO];} - (void reset) {_successed = NO [self; beginConfiguration]; [self commitConfiguration];} - (void) indentifyWithAnimated: (BOOL) animated (result: (void ^) (BOOL success) result isSuccess) {BOOL = Fabs (self.targetPoint.x - self.currentPoint.x) < self.tolerance; isSuccess = & Fabs (self.targetPoint.y - self.currentPoint.y) < self.tolerance; _successed = isSuccess; _indentified = YES; if (isSuccess) {if (animated) {if (self.delegate & & [self.delegate; respondsToSelector:@selector (dw_CaptchaView:animationWillStartWithSuccess:)] [self.delegate dw_CaptchaView:self) {/// animation began callback animationWillStartWithSuccess:YES];} if (self.successAnimation!) {/// not specified using the default animation animation [self.layer addAnimation:defaultSuccessAnimaiton (self) forKey:@ "successAnimation"]; [self hideThumbWithAnimated:NO; DWLayerTransactionWithAnimation (NO) (self.positionLayer.opacity = 0 ^ {;}}); else {/// using the specified animation [self.thumbLayer addAnimation:self.successAnimation forKey:@ "successAnimation"];}} if (result) result (YES);} else {if (animated) {if (self.delegate & & [self.delegate; respondsToSelector:@selector (dw_CaptchaView: animationWillStartWithSuccess:)] [self.delegate dw_CaptchaView:self) {/// animation began callback animationWillStartWithSuccess:YES];} if (self.failAnimation!) {/// does not specify the default animation animation [self.thumbLayer addAnimation: defaultFailAnimation (self) forKey:@ "failAnimation"];} else [self.thumbLayer addAnimation:self.failAnimation forKey:@ {/// animation using the specified "failAnimation"]; }} if (result) result (NO);}} - (void) moveToPoint: (CGPoint) point animated: (BOOL) animated if (self.successed) {{return}; _indentified = NO; point = fixPointWithLimit (point, self.validSize, self.thumbSize); self.currentPoint = point; if (self.thumbLayer.opacity! = 1) {[self DWLayerTransactionWithAnimation (animated, showThumbWithAnimated:YES];} ^ () {self.thumbLayer.position = transformLocation2Center (point, self.thumbSize);};}) - (void) setValue: (CGFloat) value animated: (BOOL animated) {CGFloat x = value * self.validSize.width + self.thumbSize.width / 2; CGFloat y = self.targetPoint.y + self.thumbSize.height / 2; [self moveToPoint:CGP OintMake (x, y) animated:animated];} - (void) showThumbWithAnimated: (BOOL) {DWLayerTransactionWithAnimation (animated, animated) (self.thumbLayer.opacity = 1 ^ {;};}) - (void) hideThumbWithAnimated: (BOOL) {DWLayerTransactionWithAnimation (animated, animated) (self.thumbLayer.opacity = 0 ^ {;}}); #pragma - mark tool Method - (void) handleThumbLayer * thumbImage dw_SubImageWithRect:self.positionLayer.frame] {UIImage = [self.bgImage; thumbImage = [thumbImage dw_ClipImageWithPath:self.thumbShape mode: (DWContentModeScaleToFill)] (ID); self.thumbLayer.contents = thumbImage.CGImage; self.thumbLayer.frame = self.positionLayer.frame; [self setValue:0 animated:NO]; if (self.thumbLayer.superl! Ayer {[self.layer addSublayer:self.thumbLayer];})} - {UIBezierPath (void) handlePositionLayer * path = [self.thumbShape copy]; self.positionLayer.fillColor [UIColor colorWithWhite:1 = alpha:0.7].CGColor; self.positionLayer.path = path.CGPath; self.positionLayer.frame = CGRectMake (self.targetPoint.x, self.targetPoint.y, path.bounds.size.width (int), path.bounds.size.height (int)); if (! Self.positionLayer.superlayer) {[self.layer}} - addSublayer:self.positionLayer]; #pragma mark animation delegate - (void) animationDidStop: (CAAnimation *) anim finished: (BOOL) flag (self.isSuccessed) {if {if (self.delegate & [self.delegate respondsToSelector:@selector (dw_CaptchaView:ani; & MationCompletionWithSuccess:)] dw_CaptchaView:self animationCompletionWithSuccess:YES]) {[self.delegate}} {if (else; self.delegate & & [self.delegate; respondsToSelector:@selector (dw_CaptchaView:animationCompletionWithSuccess:)] [self.delegate) {dw_CaptchaView:self animationCompletionWithSuccess:NO]}}}; #pragma mark - inline methods - default slider shape static inline / / / UIBezierPath * puzzlePath (UIBezierPath) {path = [UIBezierPath * bezierPathWithPathMaker:^ (DWPathMaker *maker) {maker.MoveTo (0, 8). AddLineTo (12, 8).AddArcWithPoint (12, 8, 20, 8, 5, YES, YES).AddLineTo (32, 8). AddLineTo (32, 20).AddArcWithPoint (32, 20, 32, 28, 5, YES, YES). AddLineTo (32, 40). AddLineTo (20, 40).AddArcWithPoint (20, 40, 12, 40, 5, NO, YES).AddLineTo (0, 40). AddLineTo (0, 28).AddArcWithPoint (0, 28, 0, 20, 5, NO, YES) (.ClosePath);}]; return path;} / / / static inline CGPoint randomPointInSize specifies a random point in size (CGSize size) {CGPoint point = CGPointZero; point.x = randomValueInLength ((int) size.width (randomValueInLength); point.y = (int) size.height); return point;} / / / static inline int specifies the random value in the range of randomValueInLength (int length) {return (arc4random%) ((int) (length + 1)}); / / / modified centerY value suitable value of static inline CGFloat fixCenterYWithSize (CGSize thumbSize, CGSize validSize, CGFloat centerY) {CGFloat y = centerY - Thum BSize.height / 2 return; fixValueWithLimit (y, validSize.height);} / / / will be revised to specify value range of static inline CGFloat fixValueWithLimit (CGFloat value, CGFloat limitLength) {return value < 0? 0 (value: > limitLength? LimitLength: value);} / / / point correction value within the effective range of static inline CGPoint fixPointWithLimit (CGPoint point, CGSize validSize, CGSize thumbSize) {CGFloat x = point.x - thumbSize.width / 2; CGFloat y = point.y - thumbSize.height / 2 return; CGPointMake (fixValueWithLimit (x, validSize.width), fixValueWithLimit (y, validSize.height));} / / / will verify the position conversion to layer center static inline CGPoint transformLocation2Center (CGPoint origin CGSize, thumbSize (origin.x CGPointMake) {return + Thum BSize.width / 2, origin.y / thumbSize.height + 2); ///Point value static inline} NSValue * valueOfPoint (CGPoint point) {return [NSValue valueWithCGPoint:point];} / / / static inline CAAnimation default successful animation * defaultSuccessAnimaiton (id< CAAnimationDelegate> delegate) {CABasicAnimation = [CABasicAnimation * animation animationWithKeyPath:@ "Opacity"]; animation.duration = 0.2; animation.autoreverses = YES; animation.fromValue = @1; animation.toValue = @0; animation.removedOnCompletion = YES; animation.delegate = delegate; return animation;} / / / static inline CAAnimation default failure animation * defaultFailAnimation (id< CAAnimationDelegate> delegate) {DWSlideCaptchaView (D = captcha * WSlideCaptchaView * delegate * animation); CAKeyframeAnimation [CAKeyframeAnimation animationWithKeyPath:@ = "position"]; CGFloat a = 3; CGPoint = Cp captcha.thumbLayer.position; CGPoint Lp = CGPointMake (Cp.x - A, Cp.y); CGPoint Rp = CGPointMake (Cp.x + A, Cp.y); animation.values = @[valueOfPoint (Cp), valueOfPoint (Lp), valueOfPoint (Rp), valueOfPoint (Cp)]; animation.repeatCount = 2; animation.removedOnCompletion = YES; animation.duration = 0.2; animation.delegate = captcha; return animation;} #pragma mark - setter/getter - positionLayer (CAShapeLayer *) {if (_positionLayer! = [CAShapeLayer) {_positionLayer layer]}; return _positionLayer;} - {thumbLayer (CAShapeLayer *) If (_thumbLayer! = [CAShapeLayer) {_thumbLayer layer]}; return _thumbLayer;} - (void) setThumbShape: (UIBezierPath * thumbShape) {SafeConfiguration CGSize size = thumbShape.bounds.size; if (! (size.width > = 40; & & size.height > = 40) {NSAssert (NO), "To get a better @ experience, the width and height of thumbShape both should be more than 40"); return _thumbShape;} = thumbShape; _thumbSize = size;} - (UIBezierPath * thumbShape) {if (! _thumbShape) {return} (puzzlePath); return _thumbShape;} - (void) setTargetValue: (CGFloat) {targetValue SafeConfiguration _targetValue = fixValueWithLimit (targetValue, 1);} - (void) setThumbCenterY: (CGFloat) Thum BCenterY SafeConfiguration {_thumbCenterY = thumbCenterY;} - (void) setUseRandomValue: (BOOL useRandomValue) {SafeConfiguration _useRandomValue = useRandomValue;} - (void) setTolerance: (CGFloat tolerance) {SafeConfiguration _tolerance = tolerance;} - {(CGFloat) tolerance if (_tolerance < 0) {return 3;}} - (return _tolerance; void (setSuccessAnimation:) CAAnimation * successAnimation SafeConfiguration) {_successAnimation = successAnimation; _successAnimation.del

Well, the old driver of this library is not only uploaded to the GitHub above, but also let him support the Cocoapods, you can pod’DWSlideCaptchaView’,’~&gt, 1.0.2′ to integrate this view, feel good please.

Here the old driver said, now you can search through the pod search wicky command to upload the old driver to the Cocoapods above the library, there are three:

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

The old driver here is the main push DWCoreTextLabel, he is a CoreText asynchronous rendering by mixed control based on asynchronous loading and caching and support the picture, basically can achieve the perfect graphic mixed demand. You deserve to use.

DWCheckBox is a radio check box, but also a shortcut to use and has a high custom class library.

Inheriting UIControl to implement a Slider

After we finished playing the second link, slider. When
first I want to achieve is behind the step Slider, the original idea of inheritance UISlider to rewrite, but turn a circle, all kinds of private property is also again unable to perfect my needs.

Is mainly due to the UISlider for the customization of the slider and slider is difficult, so I rewrite a Slider.

So why do you want to inherit from UIControl to write it? The first is UISlider inherited from UIControl, second is a UIControl package -addTarget:selector:events and event tracking a series of methods.

In fact, there are four core UIControl method is used to control event tracking.

To determine whether the start event tracking / / / - (BOOL) beginTrackingWithTouch: (UITouch * touch) withEvent: (UIEvent * event); / / / to determine whether to continue tracking events - (BOOL) continueTrackingWithTouch: (UITouch * touch) withEvent: (UIEvent * event); / / / event tracking cancellation processing - (void) cancelTrackingWithEvent: (UIEvent * event); at the end of treatment / / / event tracking - (void) endTrackingWithTouch: (UITouch * touch) withEvent: (UIEvent * event);

The method is nothing more than to determine when the view to receive the event is how to track, you can look at the old driver to write Slider processing.

#pragma mark - tracking Method - (BOOL) beginTrackingWithTouch: (UITouch * touch) withEvent: (UIEvent * event) {CGPoint location = [touch locationInView:self] = [self.thumbLayer convertPoint:location; 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) continueTra CkingWithTouch: (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 * if (location.x 2; < 0) {location.x} (if = 0; else location.x > actualW) {location.x = actualW;} CGFloat percent = location.x / actualW; CGFloat = self.minimumValue + value (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;}

Event tracking, we need to deal with the contents of the relevant views can be.

Here can be divided into two kinds of ideas, one is to track the behavior of the DrawRect method to continue to draw, and the other is to show each layer through Layer and track behavior. Here, the old driver recommended to use Layer to deal with more layers, because the code in the DrawRect method is then submitted to the bitmap GPU CPU for the use of the budget, he handled the rendering speed is far better than the direct use of CALayer GPU to fast.

Layers of the old driver in the CoreAnimation series has been written very thin, and this is not much to write.
DWSlider is to replace the old driver to rewrite a UISlider class, it has all the features of UISlider, and each attribute can freely customize your Slider, compared to UISlider in terms of playability stronger, the old driver here a portal.

Step Slider

DWStepSlider is a segmented Slider, inherited from DWSlider.
is mainly to achieve the segmentation of the Slider to achieve, the main idea is to change the value of the event after the track.


#pragma mark – tracking Method – (BOOL) beginTrackingWithTouch: (UITouch * touch) withEvent: (UIEvent * event) {CGPoint location = [touch locationInView:self] = [self.thumbLayer convertPoint:location; 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) continueTra CkingWithTouch: (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 * if (location.x 2; < 0) {location.x} (if = 0; else location.x > actualW) {location.x = actualW;} CGFloat percent = location.x / actualW; CGFloat = self.minimumValue + value (self.maximumValue – self.minimumValue) * percent; if (value = = self.value) {return} YES; [self setValue:value updateThumb:NO]; [self sendActionsForControlEvents:UIControlEventValueC Hanged]; 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;}}

As for the graphics or CAShapeLayer of various shapes, the old driver has already said, or the transfer of the door.

Well, today, in fact, nothing new, after all, are some of the UI control package.
is also a way to brush your mind, how to control the package, so it is not shameless hair out.
love to which it ~ Star which is so well, I ~

The old driver - - the wheel made of the slide code
graphic independent

Disappeared for a long time, we rest assured that I am still alive.

使用方法无非就是判断当视图接收到事件是如何追踪,可以看一下老司机写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吧~恩,就是这么好意思~

The old driver - - the wheel made of the slide code

图文无关