带有UIBezierPath的CAShapeLayer Shadow

fuz*_*uzz 5 objective-c cashapelayer uibezierpath

这个问题从之前的答案继续.

我有以下内容CAShapeLayer:

- (CAShapeLayer *)gaugeCircleLayer {

    if (_gaugeCircleLayer == nil) {
        _gaugeCircleLayer = [CAShapeLayer layer];
        _gaugeCircleLayer.lineWidth = self.gaugeWidth;
        _gaugeCircleLayer.fillColor = [UIColor clearColor].CGColor;
        _gaugeCircleLayer.strokeColor = self.gaugeTintColor.CGColor;
        _gaugeCircleLayer.strokeStart = 0.0f;
        _gaugeCircleLayer.strokeEnd = self.value;
        _gaugeCircleLayer.lineCap = kCALineCapRound;
        _gaugeCircleLayer.path = [self insideCirclePath].CGPath;

        CAShapeLayer *cap = [CAShapeLayer layer];
        cap.shadowColor = [UIColor blackColor].CGColor;
        cap.shadowRadius = 8.0;
        cap.shadowOpacity = 0.9;
        cap.shadowOffset = CGSizeMake(0, 0);
        cap.fillColor = [UIColor grayColor].CGColor;
        [_gaugeCircleLayer addSublayer:cap];
    }

    return _gaugeCircleLayer;
}
Run Code Online (Sandbox Code Playgroud)

然后我有以下内容UIBezierPath:

- (UIBezierPath *)insideCirclePath {

    CGPoint arcCenter = CGPointMake(CGRectGetMidX(self.bounds), CGRectGetMidY(self.bounds));
    UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:arcCenter
                                                        radius:CGRectGetWidth(self.bounds) / 2.0f
                                                    startAngle:(3.0f * M_PI_2)
                                                      endAngle:(3.0f * M_PI_2) + (2.0f * M_PI)
                                                     clockwise:YES];


    return path;
}
Run Code Online (Sandbox Code Playgroud)

这会产生如下内容:

在此输入图像描述

我想用capsublayer创建的是最后的阴影,我也有兴趣知道如何使GradientLayer工作类似于下图:

在此输入图像描述

问题是子层没有出现在任何地方,我不太清楚为什么.我也不是100%确定这是否是产生预期效果的最佳方式.

更新:

下面的代码创建了一个上限,但我不太确定如何将它添加到我的UIBezierPath正确:

let cap = CAShapeLayer()
cap.shadowColor = UIColor.blackColor().CGColor
cap.shadowRadius = 8.0
cap.shadowOpacity = 0.9
cap.shadowOffset = CGSize(width: 0, height: 0)
cap.path = UIBezierPath(ovalInRect: CGRectMake(0, 40, 20, 20)).CGPath
cap.fillColor = UIColor.grayColor().CGColor
layer.addSublayer(cap)
Run Code Online (Sandbox Code Playgroud)

rde*_*mar 2

我不知道这对您是否有用,因为它不使用 CHCircleGaugeView。我正在研究与这个问题相关的几个项目,因此我将它们混合在一起并进行了一些更改以生成一个进度视图,该视图具有颜色渐变背景,并且尖端与末端 100% 重叠。我还没有达到让圆形尖端在 0% 时消失的程度,但我最终会达到这一点。以下是两个不同进度级别的一些视图,

在此输入图像描述

在此输入图像描述

该视图是使用在drawRect 中绘制的极坐标渐变创建的,并由圆环遮盖。圆形尖端是一个单独的层,它是连接到圆中心的线末端的半圆,该圆围绕其中心旋转,并根据进度级别进行变换。这是代码,

    @implementation AnnulusProgressView{ // subclass of UIView
    int slices;
    CGFloat circleRadius;
    CAShapeLayer *maskLayer;
    CGFloat segmentAngle;
    CGFloat startAngle;
    CAShapeLayer *tipView;
    NSMutableArray *colors;
    int sign;
}


-(instancetype)initWithFrame:(CGRect)frame wantsBackgroundRing:(BOOL)wantsBackground backgroundRingColor:(UIColor *)ringColor {
    if (self = [super initWithFrame:frame]) {
        slices = 360;
        _ringThickness = 12;
        circleRadius = self.bounds.size.width/2;
        _startColor = [UIColor colorWithHue:0.24 saturation:1 brightness:0.8 alpha:1];
        _endColor = [UIColor colorWithHue:0.03 saturation:1 brightness:1 alpha:1];
        [self setupColorArray];
        _backgroundRing = wantsBackground? [self createBackgroundRingWithColor:ringColor] : nil;
        self.layer.mask = [self createAnnulusMask];
    }
    return self;
}


-(void)setStartColor:(UIColor *)startColor {
    _startColor = startColor;
    [self setupColorArray];
}


-(void)setEndColor:(UIColor *)endColor {
    _endColor = endColor;
    [self setupColorArray];
}


-(void)setupColorArray {
    colors = [NSMutableArray new];
    CGFloat startHue, startSaturation, startBrightness, startAlpha, endHue, endSaturation, endBrightness, endAlpha;

    [self.startColor getHue:&startHue saturation:&startSaturation brightness:&startBrightness alpha:&startAlpha];
    [self.endColor getHue:&endHue saturation:&endSaturation brightness:&endBrightness alpha:&endAlpha];

    for(int i=0;i<slices;i++){
        CGFloat hue = startHue + (endHue - startHue)*i/slices;
        CGFloat brightness = startBrightness + (endBrightness - startBrightness)*i/slices;
        CGFloat saturation = startSaturation + (endSaturation - startSaturation)*i/slices;
        CGFloat alpha = startAlpha + (endAlpha - startAlpha)*i/slices;
        UIColor *color = [UIColor colorWithHue:hue saturation:saturation brightness:brightness alpha:alpha];
        [colors addObject:color];
    }
    self.progress = _progress;
}



-(UIView *)createBackgroundRingWithColor:(UIColor *) color {
    UIView *bgRing = [[UIView alloc] initWithFrame:self.frame];
    bgRing.backgroundColor = color;
    bgRing.layer.mask = [self createAnnulusMask];
    [(CAShapeLayer *)bgRing.layer.mask setStrokeEnd:startAngle + 2*M_PI ];
    return bgRing;
}



-(void)didMoveToSuperview {
    if (self.backgroundRing) [self.superview insertSubview:self.backgroundRing belowSubview:self];
    tipView = [self tipView];
    [self.superview.layer addSublayer:tipView];
}



-(CAShapeLayer *)tipView {
    CAShapeLayer *tip = [CAShapeLayer layer];
    tip.frame = self.frame;
    tip.fillColor = [UIColor redColor].CGColor;
    UIBezierPath *shape = [UIBezierPath bezierPath];
    CGPoint center = CGPointMake(CGRectGetMidX(self.bounds), CGRectGetMidY(self.bounds));
    [shape moveToPoint:center];
    CGPoint bottomPoint = CGPointMake(center.x, center.y + circleRadius - self.ringThickness*2);
    CGFloat tipCenterY = bottomPoint.y + self.ringThickness - 1;
    [shape addLineToPoint: bottomPoint];
    [shape addLineToPoint:CGPointMake(bottomPoint.x+2, bottomPoint.y)];
    double fractionAlongTangent = self.ringThickness;
    [shape addCurveToPoint:CGPointMake(center.x, center.y + circleRadius) controlPoint1:CGPointMake(center.x - self.ringThickness*1.5, tipCenterY - fractionAlongTangent) controlPoint2:CGPointMake(center.x - self.ringThickness*1.5, tipCenterY + fractionAlongTangent)];
    [shape closePath];
    tip.path = shape.CGPath;
    tip.shadowColor = [UIColor darkGrayColor].CGColor;
    tip.shadowOpacity = 0.8;
    tip.shadowOffset = CGSizeMake(-6, 0);
    tip.shadowRadius = 2;
    return tip;
}



- (void)setProgress:(CGFloat)progress{
    sign = (progress >= _progress)? 1 : -1;
    [self animateProgressTo:@(progress)];
}


-(void)animateProgressTo:(NSNumber *) newValueNumber{
    float newValue = newValueNumber.floatValue;
    _progress =  (_progress + (sign * 0.1) > 1)?  1 : _progress + (sign * 0.1);
    if ((_progress > newValue && sign == 1) || (_progress < newValue && sign == -1)) {
        _progress = newValue;
    }
    maskLayer.strokeEnd = _progress;
    tipView.transform =  CATransform3DMakeRotation(-(1 - _progress + 0.002) * M_PI*2, 0, 0, 1); //the 0.002 closes a small gap between the tip and the annulus strokeEnd
    int i = (int)(_progress*(slices - 1));
    tipView.fillColor = ((UIColor *)colors[i]).CGColor;
    if (sign == 1) {
        if (_progress < newValue) {
            [self performSelector:@selector(animateProgressTo:) withObject:@(newValue) afterDelay:0.05];
        }
    }else{
        if (_progress > newValue) {
            [self performSelector:@selector(animateProgressTo:) withObject:@(newValue) afterDelay:0.05];
        }
    }

    NSLog(@"%f",_progress);
}



- (CAShapeLayer *)createAnnulusMask {
    maskLayer = [CAShapeLayer layer];
    maskLayer.frame = self.bounds;

    segmentAngle = 2*M_PI/(slices);
    startAngle = M_PI_2;
    CGFloat endAngle = startAngle + 2*M_PI;

    maskLayer.path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(CGRectGetMidX(self.bounds), CGRectGetMidY(self.bounds)) radius:circleRadius - self.ringThickness startAngle:startAngle  endAngle:endAngle clockwise:YES].CGPath;
    maskLayer.fillColor = [UIColor clearColor].CGColor;
    maskLayer.strokeColor = [UIColor blackColor].CGColor;
    maskLayer.lineWidth = self.ringThickness * 2;
    maskLayer.strokeEnd = self.progress;
    return  maskLayer;
}



-(void)drawRect:(CGRect)rect{
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    CGContextSetAllowsAntialiasing(ctx, NO);
    CGPoint center = CGPointMake(CGRectGetMidX(self.bounds), CGRectGetMidY(self.bounds));

    for(int i=0;i<slices;i++){
        CGContextSaveGState(ctx);
        UIBezierPath *path = [UIBezierPath bezierPath];
        [path moveToPoint:center];
        [path addArcWithCenter:center radius:circleRadius startAngle:startAngle endAngle:startAngle+segmentAngle clockwise:YES];
        [path addClip];
        [colors[i] setFill];
        [path fill];
        CGContextRestoreGState(ctx);

        startAngle += segmentAngle;
    }
}
Run Code Online (Sandbox Code Playgroud)