ios 如何在 CALayer 中绘制径向渐变?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/26907352/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to draw radial gradients in a CALayer?
提问by blancos
I know CAGradientLayer
doesn't support radial gradient at the moment and only has option of kCAGradientLayerAxial
.
我知道CAGradientLayer
目前不支持径向渐变,只有kCAGradientLayerAxial
.
I want something like below:
我想要像下面这样的东西:
I have looked around for this issue and found that there is a way around this. But the explanations were not clear to me. So I want to know if I can draw radial gradients using CAGradientLayer
and if so, then how to do it?
我四处寻找这个问题,发现有办法解决这个问题。但这些解释对我来说并不清楚。所以我想知道我是否可以使用绘制径向渐变CAGradientLayer
,如果可以,那么该怎么做?
回答by Mazyod
From what I understood, you just need a layer that draws a gradient, and CGContextDrawRadialGradient
works perfectly for that need. And to reiterate on what you said, CAGradientLayer
doesn't support radial gradients, and nothing we can do about that, except unnecessary swizzling that can be done cleanly with a CALayer
subclass.
据我了解,您只需要一个绘制渐变的图层,并且CGContextDrawRadialGradient
非常适合该需求。重申您所说的,CAGradientLayer
不支持径向渐变,我们对此无能为力,除了可以使用CALayer
子类干净地完成不必要的 swizzling 。
(note: the gradient drawing code was taken from here. It isn't what this answer is about.)
(注意:渐变绘制代码取自here。这不是这个答案的内容。)
viewDidLoad
:
viewDidLoad
:
GradientLayer *gradientLayer = [[GradientLayer alloc] init];
gradientLayer.frame = self.view.bounds;
[self.view.layer addSublayer:gradientLayer];
CALayer
subclass:
CALayer
子类:
- (instancetype)init
{
self = [super init];
if (self) {
[self setNeedsDisplay];
}
return self;
}
- (void)drawInContext:(CGContextRef)ctx
{
size_t gradLocationsNum = 2;
CGFloat gradLocations[2] = {0.0f, 1.0f};
CGFloat gradColors[8] = {0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.5f};
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGGradientRef gradient = CGGradientCreateWithColorComponents(colorSpace, gradColors, gradLocations, gradLocationsNum);
CGColorSpaceRelease(colorSpace);
CGPoint gradCenter= CGPointMake(CGRectGetMidX(self.bounds), CGRectGetMidY(self.bounds));
CGFloat gradRadius = MIN(self.bounds.size.width , self.bounds.size.height) ;
CGContextDrawRadialGradient (ctx, gradient, gradCenter, 0, gradCenter, gradRadius, kCGGradientDrawsAfterEndLocation);
CGGradientRelease(gradient);
}
回答by Kirualex
Here is the Swift3 code I use :
这是我使用的 Swift3 代码:
import UIKit
class RadialGradientLayer: CALayer {
required override init() {
super.init()
needsDisplayOnBoundsChange = true
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
required override init(layer: Any) {
super.init(layer: layer)
}
public var colors = [UIColor.red.cgColor, UIColor.blue.cgColor]
override func draw(in ctx: CGContext) {
ctx.saveGState()
let colorSpace = CGColorSpaceCreateDeviceRGB()
var locations = [CGFloat]()
for i in 0...colors.count-1 {
locations.append(CGFloat(i) / CGFloat(colors.count))
}
let gradient = CGGradient(colorsSpace: colorSpace, colors: colors as CFArray, locations: locations)
let center = CGPoint(x: bounds.width / 2.0, y: bounds.height / 2.0)
let radius = min(bounds.width / 2.0, bounds.height / 2.0)
ctx.drawRadialGradient(gradient!, startCenter: center, startRadius: 0.0, endCenter: center, endRadius: radius, options: CGGradientDrawingOptions(rawValue: 0))
}
}
回答by rpstw
I don't know when but now you can change CAGradientLayer
's type
to kCAGradientLayerRadial
and it works.
我不知道什么时候但现在您可以将CAGradientLayer
's更改type
为kCAGradientLayerRadial
并且它有效。
Theoretically the performance of the Core Animation way is better than Core Graphics.
理论上Core Animation方式的性能优于Core Graphics。
Some example code:
一些示例代码:
class View : UIView {
let gradientLayer = CAGradientLayer()
override init(frame: CGRect) {
super.init(frame: frame)
gradientLayer.startPoint = CGPoint(x: 0.5, y: 0.5)
gradientLayer.endPoint = CGPoint(x: 1, y: 1)
gradientLayer.locations = [
NSNumber(value: 0.6),
NSNumber(value: 0.8)
]
gradientLayer.type = .radial
gradientLayer.colors = [
UIColor.green.cgColor,
UIColor.purple.cgColor,
UIColor.orange.cgColor,
UIColor.red.cgColor
]
self.layer.addSublayer(gradientLayer)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func layoutSublayers(of layer: CALayer) {
assert(layer === self.layer)
gradientLayer.frame = layer.bounds
}
}
回答by Hayk Brsoyan
Swift 5
斯威夫特 5
import UIKit
final class RadialGradientLayer: CALayer {
let centerColor: CGColor
let edgeColor: CGColor
init(centerColor: UIColor, edgeColor: UIColor) {
self.centerColor = centerColor.cgColor
self.edgeColor = edgeColor.cgColor
super.init()
needsDisplayOnBoundsChange = true
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func draw(in ctx: CGContext) {
ctx.saveGState()
let gradient = CGGradient(colorsSpace: CGColorSpaceCreateDeviceRGB(),
colors: [centerColor, edgeColor] as CFArray,
locations: [0.0, 1.0])
let gradCenter = CGPoint(x: bounds.midX, y: bounds.midY)
let gradRadius = min(bounds.width, bounds.height)
ctx.drawRadialGradient(gradient!,
startCenter: gradCenter,
startRadius: 0.0,
endCenter: gradCenter,
endRadius: gradRadius,
options: .drawsAfterEndLocation)
}
}