如何为 ASDisplayNode 或 ASButtonNode 添加渐变
How to add gradient to ASDisplayNode or ASButtonNode
我想为 ASDisplayNode/ASButtonNode 添加渐变背景。
我试过创建一个渐变层并将其添加为这样的子层 -
CAGradientLayer *gradient = [CAGradientLayer layer];
gradient.frame = button.frame;
gradient.colors = @[[UIColor redColor], [UIColor blueColor]];
[button.view.layer insertSublayer:gradient atIndex:0];
其中 button
的类型为 ASButtonNode
,但这只是为按钮提供了白色背景。我也找不到很多文档来实现这一点。
如何在给定 UIColor
数组和 CGFloat
角度的情况下添加背景?
谢谢
您就 AsyncDisplayKit 的 GitHub 问题提出了相同的问题:
https://github.com/facebookarchive/AsyncDisplayKit/issues/3253
您的回答有 2 种可能性:
1: Create a CAGradientLayer and add it as sublayer of the node
2: Override the + (void)draw... method of the node and draw the gradient there.
第一个选项必须在主线程中,这样就无法赋予我们ASDK的强大功能。
第二个选项更复杂,但我可以 post ASDK 示例项目中的一些示例。
和
https://www.raywenderlich.com/124311/asyncdisplaykit-2-0-tutorial-getting-started
1.子类 ASDisplayNode
#import <AsyncDisplayKit/AsyncDisplayKit.h>
@interface GradientNode : ASDisplayNode
@end
2。覆盖 drawRect 方法(具有 2 种颜色的基本渐变 - 黑色到透明)
@implementation GradientNode
+(void)drawRect:(CGRect)bounds withParameters:(id)parameters isCancelled:
(asdisplaynode_iscancelled_block_t)isCancelledBlock isRasterizing:
(BOOL)isRasterizing{
CGFloat locations[2];
NSMutableArray *colors = [NSMutableArray arrayWithCapacity:2];
[colors addObject:(id)[[UIColor clearColor] CGColor]];
locations[0] = 0.0;
[colors addObject:(id)[[UIColor blackColor] CGColor]];
locations[1] = 1.0;
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGGradientRef gradient = CGGradientCreateWithColors(colorSpace,
(CFArrayRef)colors, locations);
CGContextDrawLinearGradient(ctx, gradient, CGPointZero,
CGPointMake(bounds.size.width, bounds.size.height), 0);
CGGradientRelease(gradient);
CGColorSpaceRelease(colorSpace);
}
@end
3。设置节点(重要!当使用带有清晰颜色的渐变时,否则它会绘制一个不透明的黑色视图)
_gradientNode = [GradientNode new];
_gradientNode.layerBacked = YES;
_gradientNode.opaque = NO;
Swift3.
extension UIView {
func gradient(color1: UIColor, color2: UIColor) -> CAGradientLayer {
let gradient: CAGradientLayer = CAGradientLayer()
gradient.colors = [color1.cgColor, color2.cgColor]
gradient.locations = [0.0 , 1.0]
gradient.startPoint = CGPoint(x: 0.0, y: 0.0)
gradient.endPoint = CGPoint(x: 1.0, y: 1.0)
gradient.frame = CGRect(x: 0.0, y: 0.0, width: frame.size.width, height: frame.size.height)
return gradient
}
}
示例:
let gradient = self.cardGradientNode.view.gradient(
color1: gradient.start,
color2: gradient.end
)
self.cardGradientNode.view.layer.insertSublayer(gradient, at: 0)
结果:
这是我完全基于 Texture/AsyncDisplayKit 的实现。这允许一个完全通用的渐变节点 class,它不固定整个 class 的任何值,到目前为止其他解决方案强制这样做,因为 drawRect 是一个 class 函数,而不是实例函数.
class GradientNode: ASDisplayNode {
private let startUnitPoint: CGPoint
private let endUnitPoint: CGPoint
private let colors: [UIColor]
private let locations: [CGFloat]?
override class func draw(_ bounds: CGRect, withParameters parameters: Any?, isCancelled isCancelledBlock: () -> Bool, isRasterizing: Bool) {
guard let parameters = parameters as? GradientNode else {
CCLog.assert("Expected type SimpleGradientNode to be returned")
return
}
// Calculate the start and end points
let startUnitX = parameters.startUnitPoint.x
let startUnitY = parameters.startUnitPoint.y
let endUnitX = parameters.endUnitPoint.x
let endUnitY = parameters.endUnitPoint.y
let startPoint = CGPoint(x: bounds.width * startUnitX + bounds.minX, y: bounds.height * startUnitY + bounds.minY)
let endPoint = CGPoint(x: bounds.width * endUnitX + bounds.minX, y: bounds.height * endUnitY + bounds.minY)
let context = UIGraphicsGetCurrentContext()!
context.saveGState()
context.clip(to: bounds)
guard let gradient = CGGradient(colorsSpace: CGColorSpaceCreateDeviceRGB(),
colors: parameters.colors.map { [=10=].cgColor } as CFArray,
locations: parameters.locations) else {
CCLog.assert("Unable to create CGGradient")
return
}
context.drawLinearGradient(gradient,
start: startPoint,
end: endPoint,
options: CGGradientDrawingOptions.drawsAfterEndLocation)
context.restoreGState()
}
init(startingAt startUnitPoint: CGPoint, endingAt endUnitPoint: CGPoint, with colors: [UIColor], for locations: [CGFloat]? = nil) {
self.startUnitPoint = startUnitPoint
self.endUnitPoint = endUnitPoint
self.colors = colors
self.locations = locations
super.init()
}
override func drawParameters(forAsyncLayer layer: _ASDisplayLayer) -> NSObjectProtocol? {
return self
}
只需要创建一个GradientNote并在init()函数中填入参数即可。然后把它当作一个普通的Node,让ASDK完成剩下的工作!
coverTitleBackgroundNode = GradientNode(startingAt: CGPoint(x: 0.5, y: 1.0),
endingAt: CGPoint(x: 0.5, y: 0.0),
with: [UIColor.black.withAlphaComponent(Constants.CoverTitleBackgroundBlackAlpha), UIColor.clear])
coverTitleBackgroundNode!.isLayerBacked = true
coverTitleBackgroundNode!.isOpaque = false
automaticallyManagesSubnodes = true
extension ASDisplayNode {
func gradient(from color1: UIColor, to color2: UIColor) {
DispatchQueue.main.async {
let size = self.view.frame.size
let width = size.width
let height = size.height
let gradient: CAGradientLayer = CAGradientLayer()
gradient.colors = [color1.cgColor, color2.cgColor]
gradient.locations = [0.0 , 1.0]
gradient.startPoint = CGPoint(x: 0.0, y: height/2)
gradient.endPoint = CGPoint(x: 1.0, y: height/2)
gradient.cornerRadius = 30
gradient.frame = CGRect(x: 0.0, y: 0.0, width: width, height: height)
self.view.layer.insertSublayer(gradient, at: 0)
}
}
}
示例:
node.gradient(from: .white, to: .red)
我想为 ASDisplayNode/ASButtonNode 添加渐变背景。 我试过创建一个渐变层并将其添加为这样的子层 -
CAGradientLayer *gradient = [CAGradientLayer layer];
gradient.frame = button.frame;
gradient.colors = @[[UIColor redColor], [UIColor blueColor]];
[button.view.layer insertSublayer:gradient atIndex:0];
其中 button
的类型为 ASButtonNode
,但这只是为按钮提供了白色背景。我也找不到很多文档来实现这一点。
如何在给定 UIColor
数组和 CGFloat
角度的情况下添加背景?
谢谢
您就 AsyncDisplayKit 的 GitHub 问题提出了相同的问题: https://github.com/facebookarchive/AsyncDisplayKit/issues/3253
您的回答有 2 种可能性:
1: Create a CAGradientLayer and add it as sublayer of the node
2: Override the + (void)draw... method of the node and draw the gradient there.
第一个选项必须在主线程中,这样就无法赋予我们ASDK的强大功能。 第二个选项更复杂,但我可以 post ASDK 示例项目中的一些示例。
和
https://www.raywenderlich.com/124311/asyncdisplaykit-2-0-tutorial-getting-started
1.子类 ASDisplayNode
#import <AsyncDisplayKit/AsyncDisplayKit.h>
@interface GradientNode : ASDisplayNode
@end
2。覆盖 drawRect 方法(具有 2 种颜色的基本渐变 - 黑色到透明)
@implementation GradientNode
+(void)drawRect:(CGRect)bounds withParameters:(id)parameters isCancelled:
(asdisplaynode_iscancelled_block_t)isCancelledBlock isRasterizing:
(BOOL)isRasterizing{
CGFloat locations[2];
NSMutableArray *colors = [NSMutableArray arrayWithCapacity:2];
[colors addObject:(id)[[UIColor clearColor] CGColor]];
locations[0] = 0.0;
[colors addObject:(id)[[UIColor blackColor] CGColor]];
locations[1] = 1.0;
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGGradientRef gradient = CGGradientCreateWithColors(colorSpace,
(CFArrayRef)colors, locations);
CGContextDrawLinearGradient(ctx, gradient, CGPointZero,
CGPointMake(bounds.size.width, bounds.size.height), 0);
CGGradientRelease(gradient);
CGColorSpaceRelease(colorSpace);
}
@end
3。设置节点(重要!当使用带有清晰颜色的渐变时,否则它会绘制一个不透明的黑色视图)
_gradientNode = [GradientNode new];
_gradientNode.layerBacked = YES;
_gradientNode.opaque = NO;
Swift3.
extension UIView {
func gradient(color1: UIColor, color2: UIColor) -> CAGradientLayer {
let gradient: CAGradientLayer = CAGradientLayer()
gradient.colors = [color1.cgColor, color2.cgColor]
gradient.locations = [0.0 , 1.0]
gradient.startPoint = CGPoint(x: 0.0, y: 0.0)
gradient.endPoint = CGPoint(x: 1.0, y: 1.0)
gradient.frame = CGRect(x: 0.0, y: 0.0, width: frame.size.width, height: frame.size.height)
return gradient
}
}
示例:
let gradient = self.cardGradientNode.view.gradient(
color1: gradient.start,
color2: gradient.end
)
self.cardGradientNode.view.layer.insertSublayer(gradient, at: 0)
结果:
这是我完全基于 Texture/AsyncDisplayKit 的实现。这允许一个完全通用的渐变节点 class,它不固定整个 class 的任何值,到目前为止其他解决方案强制这样做,因为 drawRect 是一个 class 函数,而不是实例函数.
class GradientNode: ASDisplayNode {
private let startUnitPoint: CGPoint
private let endUnitPoint: CGPoint
private let colors: [UIColor]
private let locations: [CGFloat]?
override class func draw(_ bounds: CGRect, withParameters parameters: Any?, isCancelled isCancelledBlock: () -> Bool, isRasterizing: Bool) {
guard let parameters = parameters as? GradientNode else {
CCLog.assert("Expected type SimpleGradientNode to be returned")
return
}
// Calculate the start and end points
let startUnitX = parameters.startUnitPoint.x
let startUnitY = parameters.startUnitPoint.y
let endUnitX = parameters.endUnitPoint.x
let endUnitY = parameters.endUnitPoint.y
let startPoint = CGPoint(x: bounds.width * startUnitX + bounds.minX, y: bounds.height * startUnitY + bounds.minY)
let endPoint = CGPoint(x: bounds.width * endUnitX + bounds.minX, y: bounds.height * endUnitY + bounds.minY)
let context = UIGraphicsGetCurrentContext()!
context.saveGState()
context.clip(to: bounds)
guard let gradient = CGGradient(colorsSpace: CGColorSpaceCreateDeviceRGB(),
colors: parameters.colors.map { [=10=].cgColor } as CFArray,
locations: parameters.locations) else {
CCLog.assert("Unable to create CGGradient")
return
}
context.drawLinearGradient(gradient,
start: startPoint,
end: endPoint,
options: CGGradientDrawingOptions.drawsAfterEndLocation)
context.restoreGState()
}
init(startingAt startUnitPoint: CGPoint, endingAt endUnitPoint: CGPoint, with colors: [UIColor], for locations: [CGFloat]? = nil) {
self.startUnitPoint = startUnitPoint
self.endUnitPoint = endUnitPoint
self.colors = colors
self.locations = locations
super.init()
}
override func drawParameters(forAsyncLayer layer: _ASDisplayLayer) -> NSObjectProtocol? {
return self
}
只需要创建一个GradientNote并在init()函数中填入参数即可。然后把它当作一个普通的Node,让ASDK完成剩下的工作!
coverTitleBackgroundNode = GradientNode(startingAt: CGPoint(x: 0.5, y: 1.0),
endingAt: CGPoint(x: 0.5, y: 0.0),
with: [UIColor.black.withAlphaComponent(Constants.CoverTitleBackgroundBlackAlpha), UIColor.clear])
coverTitleBackgroundNode!.isLayerBacked = true
coverTitleBackgroundNode!.isOpaque = false
automaticallyManagesSubnodes = true
extension ASDisplayNode {
func gradient(from color1: UIColor, to color2: UIColor) {
DispatchQueue.main.async {
let size = self.view.frame.size
let width = size.width
let height = size.height
let gradient: CAGradientLayer = CAGradientLayer()
gradient.colors = [color1.cgColor, color2.cgColor]
gradient.locations = [0.0 , 1.0]
gradient.startPoint = CGPoint(x: 0.0, y: height/2)
gradient.endPoint = CGPoint(x: 1.0, y: height/2)
gradient.cornerRadius = 30
gradient.frame = CGRect(x: 0.0, y: 0.0, width: width, height: height)
self.view.layer.insertSublayer(gradient, at: 0)
}
}
}
示例:
node.gradient(from: .white, to: .red)