带有 UIBezierPath 的 CAShapeLayer 阴影 [英] CAShapeLayer Shadow with UIBezierPath
问题描述
这个问题从,但我不太确定如何将其添加到我的 UIBezierPath
正确:
let cap = CAShapeLayer()cap.shadowColor = UIColor.blackColor().CGColorcap.shadowRadius = 8.0cap.shadowOpacity = 0.9cap.shadowOffset = CGSize(width: 0, height: 0)cap.path = UIBezierPath(ovalInRect: CGRectMake(0, 40, 20, 20)).CGPathcap.fillColor = UIColor.grayColor().CGColorlayer.addSublayer(cap)
我不知道这对您是否有用,因为它不使用 CHCircleGaugeView.我正在处理与这个问题相关的几个项目,所以我将它们混合在一起并进行了一些更改以生成一个进度视图,该视图具有颜色渐变背景,尖端与末端 100% 重叠.我还没有达到让圆形尖端在 0% 处消失的程度,但我最终会到达那里.以下是它在 2 个不同进度级别上的几个视图,
该视图是使用在 drawRect 中绘制的极坐标渐变创建的,并被环面遮蔽.圆形尖端是一个单独的层,它是一条线末端的半圆,连接到围绕其中心旋转的圆的中心,并根据进度级别进行变换.这是代码,
@implementation AnnulusProgressView{//UIView 的子类int 切片;CGFloat circleRadius;CAShapeLayer *maskLayer;CGFloat 段角;CGFloat startAngle;CAShapeLayer *tipView;NSMutableArray *colors;整数标志;}-(instancetype)initWithFrame:(CGRect)frame WantsBackgroundRing:(BOOL)wantsBackground backgroundRingColor:(UIColor *)ringColor {if (self = [super initWithFrame:frame]) {切片 = 360;_ringThickness = 12;circleRadius = self.bounds.size.width/2;_startColor = [UIColor colorWithHue:0.24 饱和度:1 亮度:0.8 alpha:1];_endColor = [UIColor colorWithHue:0.03 饱和度:1 亮度:1 alpha:1];[自设置颜色数组];_backgroundRing = 想要背景?[self createBackgroundRingWithColor:ringColor] : nil;self.layer.mask = [self createAnnulusMask];}回归自我;}-(void)setStartColor:(UIColor *)startColor {_startColor = 开始颜色;[自设置颜色数组];}-(void)setEndColor:(UIColor *)endColor {_endColor = 结束颜色;[自设置颜色数组];}-(void)setupColorArray {颜色 = [NSMutableArray 新];CGFloat startHue, startSaturation, startBrightness, startAlpha, endHue, endSaturation, endBrightness, endAlpha;[self.startColor getHue:&startHue 饱和度:&startSaturation 亮度:&startBrightness alpha:&startAlpha];[self.endColor getHue:&endHue 饱和度:&endSaturation 亮度:&endBrightness alpha:&endAlpha];for(int i=0;i 1)?1 : _progress + (符号 * 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);//0.002 关闭了尖端和环面strokeEnd 之间的小间隙int i = (int)(_progress*(slices - 1));tipView.fillColor = ((UIColor *)colors[i]).CGColor;如果(符号== 1){如果(_progress < newValue){[self performSelector:@selector(animateProgressTo:) withObject:@(newValue) afterDelay:0.05];}}别的{如果(_progress > newValue){[self performSelector:@selector(animateProgressTo:) withObject:@(newValue) afterDelay:0.05];}}NSLog(@"%f",_progress);}- (CAShapeLayer *)createAnnulusMask {maskLayer = [CAShapeLayer 层];maskLayer.frame = self.bounds;segmentAngle = 2*M_PI/(切片);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 顺时针:YES].CGPath;maskLayer.fillColor = [UIColor clearColor].CGColor;maskLayer.strokeColor = [UIColor blackColor].CGColor;maskLayer.lineWidth = self.ringThickness * 2;maskLayer.strokeEnd = self.progress;返回掩码层;}-(void)drawRect:(CGRect)rect{CGContextRef ctx = UIGraphicsGetCurrentContext();CGContextSetAllowsAntialiasing(ctx, NO);CGPoint center = CGPointMake(CGRectGetMidX(self.bounds), CGRectGetMidY(self.bounds));for(int i=0;i
This question continues from a previous answer.
I have the following 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;
}
Then I have the following 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;
}
This produces something like the following:
What I am trying to produce with the cap
sublayer is the drop shadow at the end and I'd also be interested to know how to get a GradientLayer working similar to the image below:
The problem is that the sublayer is not appearing anywhere and I'm not quite sure why. I'm also not 100% sure on whether or not this is the best way to produce the desired effect.
UPDATE:
The following bit of code creates a cap, though I'm not quite sure how to add it to my UIBezierPath
properly:
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)
I don't know if this will be useful to you, since it doesn't use the CHCircleGaugeView. I was working on several projects related to this question, so I mashed them together and made some changes to produce a progress view that has a color gradient background with a tip that overlaps the end at 100%. I haven't gotten to the point where I make the rounded tip disappear at 0%, but I'll get there eventually. Here are a couple of views of it at 2 different progress levels,
The view is created with a polar gradient drawn in drawRect, masked by an annulus. The rounded tip is a separate layer that's a half circle on the end of a line connected to the center of the circle that's revolved around its center with a transform based on the progress level. Here's the code,
@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;
}
}
这篇关于带有 UIBezierPath 的 CAShapeLayer 阴影的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!