iOS绘制渐变背景滑动条

欢迎到个人博客: liumh.com查看本文。

本文记录的是如何绘制一个背景颜色渐变的滑动条,最终的效果如下图:

iOS绘制渐变背景滑动条_第1张图片

绘制渐变背景这里用到了CAGradientLayer和CALayer的mask,首先使用两个CAGradientLayer绘制如下的背景:

iOS绘制渐变背景滑动条_第2张图片

代码如下:

    _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,如下代码所示:

    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实现,代码如下:

    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, 如下所示:

- (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

如下所示:

- (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绘制渐变背景滑动条可以下载。

本文参考:

  • iOS实现一个颜色渐变的弧形进度条

如果觉得本文对你有帮助,就请用微信打赏我吧^_^

iOS绘制渐变背景滑动条_第3张图片

你可能感兴趣的:(ios)