本文记录的是如何绘制一个背景颜色渐变的滑动条,最终的效果如下图:
背景颜色渐变的滑动条
绘制渐变背景这里用到了CAGradientLayer和CALayer的mask,首先使用两个CAGradientLayer绘制如下的背景:
渐变背景
代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 _bgLayer = [CALayer layer]; _bgLayer.bounds = CGRectMake(0, 0, CGRectGetWidth(self.bounds) - LS_HANDLE_RADIUS * 2, CGRectGetHeight(self.bounds) - LS_HANDLE_RADIUS * 2); _bgLayer.position = self.centerPoint; [self.layer addSublayer:_bgLayer]; CGColorRef topLeftColor = [UIColor blackColor].CGColor; CGColorRef bottomColor = [UIColor colorWithRed:0.5 green:0.5 blue:0.5 alpha:1].CGColor; CGColorRef topRightColor = [UIColor whiteColor].CGColor; CAGradientLayer *leftGradientLayer = [CAGradientLayer layer]; leftGradientLayer.frame = CGRectMake(0, 0, CGRectGetWidth(_bgLayer.bounds)/2, CGRectGetHeight(_bgLayer.bounds)); leftGradientLayer.colors = @[(__bridge id)topLeftColor, (__bridge id)bottomColor]; leftGradientLayer.startPoint = CGPointMake(0.5, 0); leftGradientLayer.endPoint = CGPointMake(0.5, 1); [_bgLayer addSublayer:leftGradientLayer]; CAGradientLayer *rightGradientLayer = [CAGradientLayer layer]; rightGradientLayer.frame = CGRectMake(CGRectGetWidth(_bgLayer.bounds)/2, 0, CGRectGetWidth(_bgLayer.bounds)/2, CGRectGetHeight(_bgLayer.bounds)); rightGradientLayer.colors = @[(__bridge id)bottomColor, (__bridge id)topRightColor]; rightGradientLayer.startPoint = CGPointMake(0.5, 1); rightGradientLayer.endPoint = CGPointMake(0.5, 0); [_bgLayer addSublayer:rightGradientLayer];
然后绘制maskLayer,可使用UIShapeLayer+UIBezierPath组合绘制规则图形的maskLayer,如下代码所示:
1 2 3 4 5 6 7 8 9 10 11 12 CGPoint circleCenterPoint = CGPointMake(CGRectGetWidth(_bgLayer.bounds)/2, CGRectGetHeight(_bgLayer.bounds)/2); CAShapeLayer *maskLayer = [CAShapeLayer layer]; maskLayer.position = circleCenterPoint; maskLayer.bounds = _bgLayer.bounds; maskLayer.fillColor = [UIColor clearColor].CGColor; maskLayer.strokeColor = [UIColor redColor].CGColor; maskLayer.lineCap = kCALineCapRound; maskLayer.lineWidth = self.lineWidth; UIBezierPath *maskPath = [UIBezierPath bezierPathWithArcCenter:circleCenterPoint radius:self.radius startAngle:CompassToCartesian(self.startradianFromNorth) endAngle:CompassToCartesian(self.endradianFromNorth) clockwise:true]; maskLayer.path = maskPath.CGPath; _bgLayer.mask = maskLayer;
mask
的作用是将maskLayer层不透明像素覆盖的底层显示出来,而不被不透明像素覆盖的底层则隐藏,添加mask后效果如下所示:
渐变弧线
绘制滑动条肯定有个滑动块handler,这里使用CALayer实现,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 CGPoint handleCenter = [self pointOnCircleAtRadian:self.radianFromNorth]; _outerCircleLayer = [CALayer layer]; _outerCircleLayer.bounds = CGRectMake(0, 0, LS_HANDLE_RADIUS * 2, LS_HANDLE_RADIUS * 2); _outerCircleLayer.cornerRadius = LS_HANDLE_RADIUS; _outerCircleLayer.position = handleCenter; _outerCircleLayer.shadowColor = [UIColor grayColor].CGColor; _outerCircleLayer.shadowOffset = CGSizeZero; _outerCircleLayer.shadowOpacity = 0.7; _outerCircleLayer.shadowRadius = 3; _outerCircleLayer.borderWidth = 1; _outerCircleLayer.borderColor = [UIColor grayColor].CGColor; _outerCircleLayer.backgroundColor = [UIColor whiteColor].CGColor; [self.layer addSublayer:_outerCircleLayer]; CAShapeLayer *innerCircleLayer = [CAShapeLayer layer]; innerCircleLayer.bounds = CGRectMake(0, 0, LS_HANDLE_INNER_RADIUS * 2, LS_HANDLE_INNER_RADIUS * 2); innerCircleLayer.cornerRadius = LS_HANDLE_INNER_RADIUS; innerCircleLayer.position = CGPointMake(LS_HANDLE_RADIUS, LS_HANDLE_RADIUS); innerCircleLayer.backgroundColor = self.handleFillColor.CGColor; innerCircleLayer.borderWidth = 1; innerCircleLayer.borderColor = [UIColor grayColor].CGColor; [_outerCircleLayer addSublayer:innerCircleLayer];
最后控制滑动块在制定的轨道上活动,首先控制手指触摸事件的响应范围,重载UIView的- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
,
如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event { if ([self pointInsideHandle:point withEvent:event]) { return YES; // Point is indeed within handle bounds } else { return [self pointInsideCircle:point withEvent:event]; // Return YES if point is inside slider's circle } } //检测触摸点是否在slider所在圆圈范围内 - (BOOL)pointInsideCircle:(CGPoint)point withEvent:(UIEvent *)event { CGPoint p1 = [self centerPoint]; CGPoint p2 = point; CGFloat xDist = (p2.x - p1.x); CGFloat yDist = (p2.y - p1.y); double distance = sqrt((xDist * xDist) + (yDist * yDist)); return distance < self.radius + self.lineWidth * 0.5; } //检测触摸点是否在滑动块中 - (BOOL)pointInsideHandle:(CGPoint)point withEvent:(UIEvent *)event { NSLog(@"%@", NSStringFromSelector(_cmd)); CGPoint handleCenter = [self pointOnCircleAtRadian:self.radianFromNorth]; CGFloat handleRadius = MAX(LS_HANDLE_RADIUS * 2, 44.0) * 0.5; // Adhere to apple's design guidelines - avoid making touch targets smaller than 44 points // Treat handle as a box around it's center CGRect handleRect = CGRectMake(handleCenter.x - handleRadius, handleCenter.y - handleRadius, handleRadius * 2, handleRadius * 2); return CGRectContainsPoint(handleRect, point); }
其次,限定滑动块在轨道的范围内滑动,重载UIControl的事件函数
- (BOOL)continueTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event
如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 - (BOOL)continueTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event { [super continueTrackingWithTouch:touch withEvent:event]; CGPoint lastPoint = [touch locationInView:self]; self.radianFromNorth = [self radianFromPoint:lastPoint toReferencePoint:self.centerPoint]; BOOL continueTracking = YES; if (self.radianFromNorth > self.endradianFromNorth) { self.radianFromNorth = self.endradianFromNorth; [self sendActionsForControlEvents:UIControlEventTouchDragExit]; continueTracking = NO; } else if (self.radianFromNorth < self.startradianFromNorth) { self.radianFromNorth = self.startradianFromNorth; [self sendActionsForControlEvents:UIControlEventTouchDragExit]; continueTracking = NO; } [self moveHandle]; self.currentValue = RADIAN_TO_DEGREE(self.radianFromNorth); [self sendActionsForControlEvents:UIControlEventValueChanged]; return continueTracking; }
所有的代码在ios绘制渐变背景滑动条 可以下载。
本文参考:
目前已转行教育行业,欢迎加微信交流:CaryaLiu