Как добавить градиент в ASDisplayNode или 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
угол?
Спасибо
4 ответа
Свифт 3.
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 реализация для этого. Это позволяет создать полностью универсальный класс Gradient Node, который не фиксирует никаких значений для всего класса, где до сих пор действуют другие решения, поскольку drawRect является функцией класса, а не функцией экземпляра.
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 { $0.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(). А затем относитесь к нему как к обычному узлу, и пусть 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)
Вы задали тот же вопрос о проблемах AsyncDisplayKit в GitHub: https://github.com/facebookarchive/AsyncDisplayKit/issues/3253
Вам ответили 2 варианта:
1. Создайте CAGradientLayer и добавьте его в качестве подслоя узла
2: Переопределите метод + (void)draw... для узла и нарисуйте там градиент.
Первый вариант должен быть в главном потоке, чтобы не дать нам могущественных полномочий ASDK. Второй вариант более сложный, но я могу опубликовать пример из примеров проектов 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;