带有颜色渐变的 UIBezierPath
Posted
技术标签:
【中文标题】带有颜色渐变的 UIBezierPath【英文标题】:UIBezierPath with color gradient 【发布时间】:2015-08-20 12:00:30 【问题描述】:我有一个关于 UIBezierPath 的问题。
例如我有这个路径:
现在我想要一个从白色到红色的颜色渐变。从左到右。
这是我的代码:
UIBezierPath *bezierPath;
bezierPath = [UIBezierPath bezierPathWithArcCenter:_center radius:_radius startAngle:((4 * angle)) endAngle:(((20) * angle)) clockwise:YES];
[bezierPath addLineToPoint:_center];
[bezierPath closePath];
UIColor *color = [UIColor colorWithHue:0/sectors saturation:1. brightness:1. alpha:1];
[color setFill];
[color setStroke];
[bezierPath fill];
[bezierPath stroke];
谁能帮帮我?
编辑 1:
我有这个色轮:
UIBezierPath *bezierPath;
for ( int i = 0; i < 360; i++)
bezierPath = [UIBezierPath bezierPathWithArcCenter:_center radius:_radius startAngle:((i * angle)) endAngle:(((i + 1) * angle)) clockwise:YES];
[bezierPath addLineToPoint:_center];
[bezierPath closePath];
UIColor *color = [UIColor colorWithHue:i/sectors saturation:1. brightness:1. alpha:1];
[color setFill];
[color setStroke];
[bezierPath fill];
[bezierPath stroke];
但我想要这个:(使用白色渐变)
【问题讨论】:
您需要它作为图像还是绘图?如果图像/视图可以接受,您是否考虑过添加径向渐变:***.com/questions/23494063/… 首先,使用CGContextAddArc
而不是UIBezierPath
。这将使您的绘图更加精确。其次,您可能希望在中心绘制几个具有不同半径(递减和 alpha 递增)的白色圆圈,以获得漂亮的白色中心。
我需要它作为绘图。但是谢谢!
@OlegShanyuk 谢谢,但我不知道这是怎么回事
当靠近中心时,您需要在使用白色背景时更改亮度或更改 alpha。
【参考方案1】:
使用CAGradientLayer
并使用CAShapeLayer
将其屏蔽
- (void)addCircle
CAShapeLayer *shapeLayer = [CAShapeLayer new];
shapeLayer.path = [UIBezierPath bezierPathWithOvalInRect:CGRectInset(CGRectMake(10, 10, 100, 100), 4, 4)].CGPath;
shapeLayer.strokeColor = [UIColor redColor].CGColor;
shapeLayer.contentsScale = [UIScreen mainScreen].scale;
shapeLayer.shouldRasterize = NO;
CAGradientLayer *_gradientLayer = [CAGradientLayer layer];
_gradientLayer.frame =self.view.bounds;
_gradientLayer.startPoint = CGPointMake(0.0, 1);
_gradientLayer.endPoint = CGPointMake(1, 0);
_gradientLayer.colors = @[(id)[UIColor blueColor].CGColor,(id)[UIColor redColor].CGColor];
//Add gradient layer to view
[self.view.layer addSublayer:_gradientLayer];
_gradientLayer.mask = shapeLayer;
上面的方法会添加一个三角形,可能你需要改变起点和终点。您也可以将渐变值更改为您需要的任何值。
Apple Docs
CAGradientLayer Tutorial
更新 更新后更清楚的是它不是你想要的三角形,但你需要的是CAGradientLayer
和CAShapeLayer
,你需要遵循相同的方法,你可以添加渐变不同的颜色和位置(停止)(如果您要添加位置,请确保位置和颜色相同),然后用 CAShapeLayer
将其遮盖住。
【讨论】:
我得到一个 EXC_BAD_ACCESS。 您在哪里获得 xc_bad_access? 我添加了我的答案,复制粘贴此方法并从 viewDidAppear 或您需要的任何地方调用此方法,它将添加 查看我编辑的问题。我可以用你的解决方案来解决这个问题吗? 所以它不是三角形的整个圆,是的,你可以用 CAGradientLayer 来做这个,画圆不是问题,只需用 CAShapeLayer 和蒙版渐变层创建一个圆,创建渐变添加你所有的颜色和也可以使用位置。【参考方案2】:你可以试一试:)
- (void)drawRect:(CGRect)rect
CGFloat arcStep = (M_PI *2) / 360; // M_PI*2 is equivalent of full cirle
BOOL clocklwise = NO;
CGFloat x = CGRectGetWidth(rect) / 2; // circle's center
CGFloat y = CGRectGetHeight(rect) / 2; // circle's center
CGFloat radius = MIN(x, y) / 2;
CGContextRef ctx = UIGraphicsGetCurrentContext();
// draw colorful circle
CGContextSetLineWidth(ctx, radius*2);
for (CGFloat i = 0; i < 360; i+=1)
UIColor* c = [UIColor colorWithHue:i/360 saturation:1. brightness:1. alpha:1];
CGContextSetStrokeColorWithColor(ctx, c.CGColor);
CGFloat startAngle = i * arcStep;
CGFloat endAngle = startAngle + arcStep + 0.02;
CGContextAddArc(ctx, x, y, radius, startAngle, endAngle, clocklwise);
CGContextStrokePath(ctx);
// drawing circles then, you might want few of them - smaller radius and less alpha with each step
UIColor* c = [[UIColor whiteColor] colorWithAlphaComponent: 0.03];
for (CGFloat fillRadius = radius/2; fillRadius > 0; fillRadius -= 1.f)
CGContextSetLineWidth(ctx, fillRadius*2);
CGContextSetStrokeColorWithColor(ctx, c.CGColor);
CGContextAddArc(ctx, x, y, fillRadius, 0, M_PI * 2, clocklwise);
CGContextStrokePath(ctx);
【讨论】:
什么是'ctx'? Atm 我这样做: UIGraphicsBeginImageContextWithOptions(CGSizeMake(size.width, size.height), YES, 0.0);等等。 x/y 是怎么回事? x, y - 这是你的圆心; ctx - 这是你的图形上下文 抱歉,我完全是图形学的初学者。如何将此添加到我的视图中?我的旧代码位于 UIView 子类的 drawRect 方法中。我该如何处理? 好的,您也可以在drawRect:
中这样做,让我们再更新一次示例...
@DanielChristoph 尝试复制粘贴【参考方案3】:
Oleg 关于饱和度(白色渐变)的另一种回答,我觉得更令人愉悦,在 Swift (3) 中。
如果您想要更大的白色圆圈(例如 0.2 处的第二个白色阶梯),您可以在渐变中添加阶梯
import UIKit
class HSView: UIView
override func draw(_ rect: CGRect)
let arcStep = 2 * CGFloat.pi / 360
let isClockwise = false
let x = rect.width / 2
let y = rect.height / 2
let radius = min(x, y) / 2
let ctx = UIGraphicsGetCurrentContext()
ctx?.setLineWidth(2 * radius)
for i in 0..<360
let color = UIColor(hue: CGFloat(i)/360, saturation: 1, brightness: 1, alpha: 1)
let startAngle = CGFloat(i) * arcStep
let endAngle = startAngle + arcStep + 0.02
ctx?.setStrokeColor(color.cgColor)
ctx?.addArc(center: CGPoint(x: x, y: y), radius: radius, startAngle: startAngle, endAngle: endAngle, clockwise: isClockwise)
ctx?.strokePath()
let gradient = CGGradient(colorsSpace: UIColor.white.cgColor.colorSpace,
colors: [
UIColor.white.cgColor,
UIColor.white.withAlphaComponent(0).cgColor,
] as CFArray,
locations: [
0,
1,
]
)
ctx?.drawRadialGradient(gradient!, startCenter: CGPoint(x: x, y: y), startRadius: 0, endCenter: CGPoint(x: x, y: y), endRadius: 2 * radius, options: .drawsAfterEndLocation)
【讨论】:
【参考方案4】:你可以试试这个:
//// General Declarations
CGContextRef context = UIGraphicsGetCurrentContext();
//// Shadow Declarations
NSShadow* shadow = [[NSShadow alloc] init];
[shadow setShadowColor: UIColor.whiteColor];
[shadow setShadowOffset: CGSizeMake(2.1, -4.1)];
[shadow setShadowBlurRadius: 5];
//// Bezier Drawing
UIBezierPath* bezierPath = UIBezierPath.bezierPath;
[UIColor.blackColor setStroke];
bezierPath.lineWidth = 1;
[bezierPath stroke];
//// Bezier 2 Drawing
UIBezierPath* bezier2Path = UIBezierPath.bezierPath;
[bezier2Path moveToPoint: CGPointMake(170.5, 59.5)];
[bezier2Path addCurveToPoint: CGPointMake(170.5, 71.5) controlPoint1: CGPointMake(173.5, 65.5) controlPoint2: CGPointMake(170.5, 71.5)];
[bezier2Path addLineToPoint: CGPointMake(155.5, 57.5)];
[bezier2Path addLineToPoint: CGPointMake(170.5, 59.5)];
[UIColor.redColor setFill];
[bezier2Path fill];
////// Bezier 2 Inner Shadow
CGContextSaveGState(context);
UIRectClip(bezier2Path.bounds);
CGContextSetShadowWithColor(context, CGSizeZero, 0, NULL);
CGContextSetAlpha(context, CGColorGetAlpha([shadow.shadowColor CGColor]));
CGContextBeginTransparencyLayer(context, NULL);
UIColor* opaqueShadow = [shadow.shadowColor colorWithAlphaComponent: 1];
CGContextSetShadowWithColor(context, shadow.shadowOffset, shadow.shadowBlurRadius, [opaqueShadow CGColor]);
CGContextSetBlendMode(context, kCGBlendModeSourceOut);
CGContextBeginTransparencyLayer(context, NULL);
[opaqueShadow setFill];
[bezier2Path fill];
CGContextEndTransparencyLayer(context);
CGContextEndTransparencyLayer(context);
CGContextRestoreGState(context);
结果将是:
【讨论】:
您需要将上述代码放在 UIView.m 文件中的 drawRect 方法中,并使其成为您的 uiview 的文件所有者【参考方案5】:您将使用 QuartsCore 将其存档。如果你想用你的图形获取图像,你可以调用 UIGraphicsBeginImageContext(),如果你想在 UIView 上绘制它,你应该重载方法 - UIView 的 (void)drawRect:(CGRect)rect。 您可以将路径添加到上下文,并将其用于clipping 上下文(不要忘记之前保存上下文状态)。之后就可以画gradient了。渐变将被路径剪裁。
你会得到这样的东西:
CGPathRef path = [bezierPath CGPath];
CGContextSaveGState(context);
CGContextAddPath(context, path);
CGContextClip(context);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
NSArray *colors = [NSArray arrayWithObjects:(id)[UIColor redColor].CGColor, (id)[UIColor blueColor].CGColor, nil];
CGGradientRef gradient = CGGradientCreateWithColors( colorSpace, (CFArrayRef)colors, NULL);
CGColorSpaceRelease(colorSpace);
colorSpace = NULL;
CGContextDrawLinearGradient(context, gradient, CGPointMake(0.0, 0.0), CGPointMake(100.0, 100.0), kNilOptions);
CGContextRestoreGState(context);
【讨论】:
以上是关于带有颜色渐变的 UIBezierPath的主要内容,如果未能解决你的问题,请参考以下文章