iphone - color - swift gradient background
Aplicar un degradado a CAShapeLayer (3)
Esta es una gran solución, pero puede encontrar problemas inesperados si está creando una categoría en CAShapeLayer donde no tiene la vista inmediatamente.
Consulte Configuración del marco correcto de CAShapeLayer recién creado
En la línea inferior, obtenga los límites de la ruta, establezca el marco de la máscara de degradado usando los límites de la ruta y traduzca según sea necesario. Lo bueno es que al usar los límites de la ruta en lugar de cualquier otro marco, el gradiente solo se ajustará a los límites de la ruta (suponiendo que eso es lo que quieres).
// Category on CAShapeLayer
CGRect pathBounds = CGPathGetBoundingBox(self.path);
CAShapeLayer *gradientMask = [CAShapeLayer layer];
gradientMask.fillColor = [[UIColor blackColor] CGColor];
gradientMask.frame = CGRectMake(0, 0, pathBounds.size.width, pathBounds.size.height);
gradientMask.path = self.path;
CAGradientLayer *gradientLayer = [CAGradientLayer layer];
gradientLayer.startPoint = CGPointMake(0.5,1.0);
gradientLayer.endPoint = CGPointMake(0.5,0.0);
gradientLayer.frame = CGRectMake(0, 0, pathBounds.size.width, pathBounds.size.height);
NSMutableArray *colors = [NSMutableArray array];
for (int i = 0; i < 10; i++) {
[colors addObject:(id)[[UIColor colorWithHue:(0.1 * i) saturation:1 brightness:.8 alpha:1] CGColor]];
}
gradientLayer.colors = colors;
[gradientLayer setMask:gradientMask];
[self addSublayer:gradientLayer];
¿Alguien tiene alguna experiencia en aplicar un degradado a un CAShapeLayer? CAShapeLayer es una clase de capa fantástica, pero parece que solo es compatible con la coloración de relleno sólido, mientras que me gustaría que tuviera un relleno de degradado (en realidad, un degradado animable).
Todo lo que tiene que ver con CAShapeLayer (sombras, formas, color de trazo, ruta de forma animable) es fantástico.
He intentado colocar un CAGradientLayer dentro de un CAShapeLayer, o incluso establecer el CAShapeLayer como la máscara del GradientLayer y agregar ambos a una capa de contenedor, pero estos no tienen el resultado correcto.
¿Debo subclasificar CAShapeLayer o hay una mejor manera de avanzar?
Gracias.
Muchas gracias a @Palimondo por una gran respuesta!
En caso de que alguien esté buscando el código de animación Swift 4 + fill de esta solución:
let myView = UIView(frame: .init(x: 0, y: 0, width: 200, height: 150))
view.addSubview(myView)
myView.center = view.center
// Start and finish point
let startPoint = CGPoint(x: myView.bounds.minX, y: myView.bounds.midY)
let finishPoint = CGPoint(x: myView.bounds.maxX, y: myView.bounds.midY)
// Path
let path = UIBezierPath()
path.move(to: startPoint)
path.addLine(to: finishPoint)
// Gradient Mask
let gradientMask = CAShapeLayer()
let lineHeight = myView.frame.height
gradientMask.fillColor = UIColor.clear.cgColor
gradientMask.strokeColor = UIColor.black.cgColor
gradientMask.lineWidth = lineHeight
gradientMask.frame = myView.bounds
gradientMask.path = path.cgPath
// Gradient Layer
let gradientLayer = CAGradientLayer()
gradientLayer.startPoint = CGPoint(x: 0.0, y: 0.5)
gradientLayer.endPoint = CGPoint(x: 1.0, y: 0.5)
// make sure to use .cgColor
gradientLayer.colors = [UIColor.red.cgColor, UIColor.green.cgColor]
gradientLayer.frame = myView.bounds
gradientLayer.mask = gradientMask
myView.layer.addSublayer(gradientLayer)
// Corner radius
myView.layer.cornerRadius = 10
myView.clipsToBounds = true
Extra . En caso de que también necesite una "animación de relleno", agregue estas líneas:
// Filling animation
let animation = CABasicAnimation(keyPath: "strokeEnd")
animation.fromValue = 0
animation.duration = 10
gradientMask.add(animation, forKey: "LineAnimation")
Podría usar la ruta de su forma para crear una capa de enmascaramiento y aplicarla en la capa de degradado, así:
UIView *v = [[UIView alloc] initWithFrame:self.window.frame];
CAShapeLayer *gradientMask = [CAShapeLayer layer];
gradientMask.fillColor = [[UIColor clearColor] CGColor];
gradientMask.strokeColor = [[UIColor blackColor] CGColor];
gradientMask.lineWidth = 4;
gradientMask.frame = CGRectMake(0, 0, v.bounds.size.width, v.bounds.size.height);
CGMutablePathRef t = CGPathCreateMutable();
CGPathMoveToPoint(t, NULL, 0, 0);
CGPathAddLineToPoint(t, NULL, v.bounds.size.width, v.bounds.size.height);
gradientMask.path = t;
CAGradientLayer *gradientLayer = [CAGradientLayer layer];
gradientLayer.startPoint = CGPointMake(0.5,1.0);
gradientLayer.endPoint = CGPointMake(0.5,0.0);
gradientLayer.frame = CGRectMake(0, 0, v.bounds.size.width, v.bounds.size.height);
NSMutableArray *colors = [NSMutableArray array];
for (int i = 0; i < 10; i++) {
[colors addObject:(id)[[UIColor colorWithHue:(0.1 * i) saturation:1 brightness:.8 alpha:1] CGColor]];
}
gradientLayer.colors = colors;
[gradientLayer setMask:gradientMask];
[v.layer addSublayer:gradientLayer];
Si también desea utilizar las sombras, tendría que colocar un "duplicado" de la capa de forma debajo de la capa de degradado, reciclando la misma referencia de ruta.