Crear mediante programación una UIView con degradado de color

Respuestas:

694

C objetivo:

UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 50)];
CAGradientLayer *gradient = [CAGradientLayer layer];

gradient.frame = view.bounds;
gradient.colors = @[(id)[UIColor whiteColor].CGColor, (id)[UIColor blackColor].CGColor];

[view.layer insertSublayer:gradient atIndex:0];

Rápido:

let view = UIView(frame: CGRect(x: 0, y: 0, width: 320, height: 50))
let gradient = CAGradientLayer()

gradient.frame = view.bounds
gradient.colors = [UIColor.white.cgColor, UIColor.black.cgColor]

view.layer.insertSublayer(gradient, at: 0)

Información : use startPoint y endPoint para cambiar la dirección del gradiente .

Si hay otras vistas agregadas a esto UIView(como a UILabel), es posible que desee considerar configurar el color de fondo de esos UIViewpara [UIColor clearColor]que se presente la vista de degradado en lugar del color de fondo para las vistas secundarias. El uso clearColortiene un ligero impacto en el rendimiento.

Arslan Ali
fuente
13
+1 para la menor cantidad de código de todas las soluciones. Acabo de agregar a mi controlador de vista existente, cambié las 2 referencias viewa self.viewy funcionó de maravilla :)
Ergin
44
También es relevante dónde agregar este código. Necesitaba la siguiente publicación para que esto funcionara: stackoverflow.com/a/20059268/1480518
Garrett Disco
13
¡Esto me ayudó mucho! ¡Perdí la parte de CGColor en cualquier otro lugar! Gracias
Gyfis
48
No olvide usar 'startPoint' y 'endPoint' para cambiar la dirección del gradiente. Los valores predeterminados son (0.5, 0) y (0.5,1) - de arriba hacia abajo.
Valentin Shamardin
12
Cuando mi UIView está usando diseño automático, también tuve que llamar gradient.frame = view.boundsen viewDidAppear()y en didRotateFromInterfaceOrientation(), o bien el gradiente no se dimensiona adecuadamente.
EricRobertBrewer
70

Puedes crear una clase personalizada GradientView:

Swift 5

class GradientView: UIView {
    override open class var layerClass: AnyClass {
       return CAGradientLayer.classForCoder()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        let gradientLayer = layer as! CAGradientLayer
        gradientLayer.colors = [UIColor.white.cgColor, UIColor.black.cgColor]
    }
}

En el guión gráfico, establezca el tipo de clase en cualquier vista que desee tener un fondo degradado:

ingrese la descripción de la imagen aquí

Esto es mejor de las siguientes maneras:

  • No es necesario establecer el marco de CLayer
  • Use NSConstraintcomo de costumbre en elUIView
  • No es necesario crear subcapas (menos uso de memoria)
Yuchen Zhong
fuente
1
En Swift 3, layerClassya no es una función, es una propiedad, por lo que debe anularla como una propiedad: stackoverflow.com/questions/28786597/… . También debe implementar override init(frame: CGRect), verifique esta respuesta: stackoverflow.com/questions/27374330/… . ¡Gracias!
LaloLoop
Hola @LaloLoop, gracias por el comentario! He actualizado el código. Sin init(frame:CGRect)embargo , no creo que tenga que anular . Probé el código actualizado y funciona bien.
Yuchen Zhong
@Yuchen Zhong Se bloquea en IB, pero funciona en la aplicación. ¿Alguna razón por la que no se procesa en IB si @IBDesignablese usa?
Alexander Volkov
@AlexanderVolkov ¿Probablemente algún otro problema? Lo hemos estado utilizando así en el guión gráfico y no parece tener ningún problema. Puede depurar su guión gráfico y ver qué línea lo está bloqueando.
Yuchen Zhong
1
Mejor solución !
Baran Emre
40

Prueba esto, funcionó como un encanto para mí,

C objetivo

He configurado el color de fondo del degradado RGB en UIview

   UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0,0,320,35)];
   CAGradientLayer *gradient = [CAGradientLayer layer];
   gradient.frame = view.bounds;
   gradient.startPoint = CGPointZero;
   gradient.endPoint = CGPointMake(1, 1);
   gradient.colors = [NSArray arrayWithObjects:(id)[[UIColor colorWithRed:34.0/255.0 green:211/255.0 blue:198/255.0 alpha:1.0] CGColor],(id)[[UIColor colorWithRed:145/255.0 green:72.0/255.0 blue:203/255.0 alpha:1.0] CGColor], nil];
   [view.layer addSublayer:gradient];

ingrese la descripción de la imagen aquí

ACTUALIZADO: - Swift3 +

Código : -

 var gradientView = UIView(frame: CGRect(x: 0, y: 0, width: 320, height: 35))
 let gradientLayer:CAGradientLayer = CAGradientLayer()
 gradientLayer.frame.size = self.gradientView.frame.size
 gradientLayer.colors = 
 [UIColor.white.cgColor,UIColor.red.withAlphaComponent(1).cgColor] 
//Use diffrent colors
 gradientView.layer.addSublayer(gradientLayer)

ingrese la descripción de la imagen aquí

Puede agregar el punto inicial y final del color degradado.

  gradientLayer.startPoint = CGPoint(x: 0.0, y: 1.0)
  gradientLayer.endPoint = CGPoint(x: 1.0, y: 1.0)

ingrese la descripción de la imagen aquí

Para una descripción más detallada, consulte CAGradientLayer Doc

Espero que esto sea de ayuda para alguien.

Jaywant Khedkar
fuente
36

Este es mi enfoque recomendado.

Para promover la reutilización, diría que cree una categoría CAGradientLayery agregue sus gradientes deseados como métodos de clase. Especifíquelos en el headerarchivo así:

#import <QuartzCore/QuartzCore.h>

@interface CAGradientLayer (SJSGradients)

+ (CAGradientLayer *)redGradientLayer;
+ (CAGradientLayer *)blueGradientLayer;
+ (CAGradientLayer *)turquoiseGradientLayer;
+ (CAGradientLayer *)flavescentGradientLayer;
+ (CAGradientLayer *)whiteGradientLayer;
+ (CAGradientLayer *)chocolateGradientLayer;
+ (CAGradientLayer *)tangerineGradientLayer;
+ (CAGradientLayer *)pastelBlueGradientLayer;
+ (CAGradientLayer *)yellowGradientLayer;
+ (CAGradientLayer *)purpleGradientLayer;
+ (CAGradientLayer *)greenGradientLayer;

@end

Luego, en su archivo de implementación, especifique cada gradiente con esta sintaxis:

+ (CAGradientLayer *)flavescentGradientLayer
{
    UIColor *topColor = [UIColor colorWithRed:1 green:0.92 blue:0.56 alpha:1];
    UIColor *bottomColor = [UIColor colorWithRed:0.18 green:0.18 blue:0.18 alpha:1];

    NSArray *gradientColors = [NSArray arrayWithObjects:(id)topColor.CGColor, (id)bottomColor.CGColor, nil];
    NSArray *gradientLocations = [NSArray arrayWithObjects:[NSNumber numberWithInt:0.0],[NSNumber numberWithInt:1.0], nil];

    CAGradientLayer *gradientLayer = [CAGradientLayer layer];
    gradientLayer.colors = gradientColors;
    gradientLayer.locations = gradientLocations;

    return gradientLayer;
}

Luego simplemente importe esta categoría en su ViewControllero cualquier otra requerida subclass, y úsela así:

CAGradientLayer *backgroundLayer = [CAGradientLayer purpleGradientLayer];
backgroundLayer.frame = self.view.frame;
[self.view.layer insertSublayer:backgroundLayer atIndex:0];
Sam Fischer
fuente
¿Dónde deberías poner el código para usarlo? ¿Qué método de ciclo de vida? viewdidappear hace que parezca un segundo demasiado tarde. viewdidload y viewdidappear hacen que no funcione mientras gira. viewdidlayoutsubviews funciona mejor para la rotación, pero aún así se ve un poco entrecortado.
Adam Johns
Yo personalmente lo puseviewDidLoad
Sam Fischer
1
Cuando lo puse viewDidLoad, no funcionó si la aplicación se lanzó en orientación horizontal. Mi solución fue hacer que el marco de la capa de fondo sea más ancho que el view.frame para compensar otras orientaciones.
Adam Johns
2
viewDidLoad funciona, solo tiene que configurar la máscara AutoResizingMask usando [backgroundLayer setAutoresizingMask: UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight];
ekscrypto
21

Como solo necesitaba un tipo de degradado en mi aplicación, creé una subclase de UIView y preconfiguré la capa de degradado en la inicialización con colores fijos. Los inicializadores de UIView llaman al método configureGradientLayer , que configura CAGradientLayer:

DDGradientView.h:

#import <UIKit/UIKit.h>

@interface DDGradientView : UIView {

}
@end

DDGradientView.m:

#import "DDGradientView.h"

@implementation DDGradientView

// Change the views layer class to CAGradientLayer class
+ (Class)layerClass
{
    return [CAGradientLayer class];
}

- (instancetype)initWithCoder:(NSCoder *)aDecoder {
    self = [super initWithCoder:aDecoder];
    if(self) {
        [self configureGradientLayer];
    }
    return self;
}

- (instancetype)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    if(self) {
        [self configureGradientLayer];
    }
    return self;
}

// Make custom configuration of your gradient here   
- (void)configureGradientLayer {
    CAGradientLayer *gLayer = (CAGradientLayer *)self.layer;
    gLayer.colors = [NSArray arrayWithObjects:(id)[[UIColor whiteColor] CGColor], (id)[[UIColor lightGrayColor] CGColor], nil];
}
@end
blauzahn
fuente
El nombre del método initGradientLayeres similar a un inicializador. No creo que sea muy adecuado.
DawnSong
@DawnSong Buen punto, lo cambié a 'configureGradientLayer'.
blauzahn
12

Implementación rápida:

var gradientLayerView: UIView = UIView(frame: CGRectMake(0, 0, view.bounds.width, 50))
var gradient: CAGradientLayer = CAGradientLayer()
gradient.frame = gradientLayerView.bounds
gradient.colors = [UIColor.grayColor().CGColor, UIColor.clearColor().CGColor]
gradientLayerView.layer.insertSublayer(gradient, atIndex: 0)
self.view.layer.insertSublayer(gradientLayerView.layer, atIndex: 0)
Siva Visakan
fuente
11

He extendido un poco la respuesta aceptada usando la funcionalidad de extensión de Swift, así como una enumeración.

Ah, y si está utilizando Storyboard como lo hace, asegúrese de llamar gradientBackground(from:to:direction:)en viewDidLayoutSubviews()o posterior.

Swift 3

enum GradientDirection {
    case leftToRight
    case rightToLeft
    case topToBottom
    case bottomToTop
}

extension UIView {
    func gradientBackground(from color1: UIColor, to color2: UIColor, direction: GradientDirection) {
        let gradient = CAGradientLayer()
        gradient.frame = self.bounds
        gradient.colors = [color1.cgColor, color2.cgColor]

        switch direction {
        case .leftToRight:
            gradient.startPoint = CGPoint(x: 0.0, y: 0.5)
            gradient.endPoint = CGPoint(x: 1.0, y: 0.5)
        case .rightToLeft:
            gradient.startPoint = CGPoint(x: 1.0, y: 0.5)
            gradient.endPoint = CGPoint(x: 0.0, y: 0.5)
        case .bottomToTop:
            gradient.startPoint = CGPoint(x: 0.5, y: 1.0)
            gradient.endPoint = CGPoint(x: 0.5, y: 0.0)
        default:
            break
        }

        self.layer.insertSublayer(gradient, at: 0)
    }
}
flocbit
fuente
10

He implementado esto rápidamente con una extensión:

Swift 3

extension UIView {
    func addGradientWithColor(color: UIColor) {
        let gradient = CAGradientLayer()
        gradient.frame = self.bounds
        gradient.colors = [UIColor.clear.cgColor, color.cgColor]

        self.layer.insertSublayer(gradient, at: 0)
    }
}

Swift 2.2

extension UIView {
    func addGradientWithColor(color: UIColor) {
        let gradient = CAGradientLayer()
        gradient.frame = self.bounds
        gradient.colors = [UIColor.clearColor().CGColor, color.CGColor]

        self.layer.insertSublayer(gradient, atIndex: 0)
    }
}

No, puedo establecer un gradiente en cada vista de esta manera:

myImageView.addGradientWithColor(UIColor.blue)
patrickS
fuente
La llamada Swift3 debe ser como: myImageView.addGradientWithColor (color: UIColor.blue)
mgyky
8

Un enfoque rápido

Esta respuesta se basa en las respuestas anteriores y proporciona una implementación para tratar el problema de que el gradiente no se aplique correctamente durante la rotación. Satisface este problema cambiando la capa de degradado a un cuadrado para que la rotación en todas las direcciones resulte en un degradado correcto. La firma de la función incluye un argumento variado Swift que le permite a uno pasar tantos CGColorRef (CGColor) como sea necesario (ver uso de muestra). También se proporciona un ejemplo como una extensión Swift para que se pueda aplicar un degradado a cualquier UIView.

   func configureGradientBackground(colors:CGColorRef...){

        let gradient: CAGradientLayer = CAGradientLayer()
        let maxWidth = max(self.view.bounds.size.height,self.view.bounds.size.width)
        let squareFrame = CGRect(origin: self.view.bounds.origin, size: CGSizeMake(maxWidth, maxWidth))
        gradient.frame = squareFrame

        gradient.colors = colors
        view.layer.insertSublayer(gradient, atIndex: 0)
    }

Usar:

a la vistaDidLoad ...

  override func viewDidLoad() {
        super.viewDidLoad()
        configureGradientBackground(UIColor.redColor().CGColor, UIColor.whiteColor().CGColor)
  }

Implementación de extensión

extension CALayer {


    func configureGradientBackground(colors:CGColorRef...){

        let gradient = CAGradientLayer()

        let maxWidth = max(self.bounds.size.height,self.bounds.size.width)
        let squareFrame = CGRect(origin: self.bounds.origin, size: CGSizeMake(maxWidth, maxWidth))
        gradient.frame = squareFrame

        gradient.colors = colors

        self.insertSublayer(gradient, atIndex: 0)
    }

}

Ejemplo de caso de uso de extensión:

 override func viewDidLoad() {
        super.viewDidLoad()

        self.view.layer.configureGradientBackground(UIColor.purpleColor().CGColor, UIColor.blueColor().CGColor, UIColor.whiteColor().CGColor)
 }

Lo que significa que el fondo del degradado ahora se puede aplicar a cualquier UIControl ya que todos los controles son UIViews (o una subclase) y todas las UIViews tienen CALayers.

Swift 4

Implementación de extensión

extension CALayer {
    public func configureGradientBackground(_ colors:CGColor...){

        let gradient = CAGradientLayer()

        let maxWidth = max(self.bounds.size.height,self.bounds.size.width)
        let squareFrame = CGRect(origin: self.bounds.origin, size: CGSize(width: maxWidth, height: maxWidth))
        gradient.frame = squareFrame

        gradient.colors = colors

        self.insertSublayer(gradient, at: 0)
    }    
}

Ejemplo de caso de uso de extensión:

override func viewDidLoad() {
    super.viewDidLoad()

    self.view.layer.configureGradientBackground(UIColor.purple.cgColor, UIColor.blue.cgColor, UIColor.white.cgColor)
}
Tommie C.
fuente
5

Lo que estás buscando es CAGradientLayer. Todos UIViewtienen una capa: en esa capa puedes agregar subcapas, así como puedes agregar subvistas. Un tipo específico es el CAGradientLayer, donde le das una variedad de colores para graduarse.

Un ejemplo es este contenedor simple para una vista de degradado:

http://oleb.net/blog/2010/04/obgradientview-a-simple-uiview-wrapper-for-cagradientlayer/

Tenga en cuenta que debe incluir el marco QuartZCore para acceder a todas las partes de la capa de una UIView.

Kendall Helmstetter Gelner
fuente
4

Swift 4:

Muestra el gradiente en IB correctamente:

@IBDesignable public class GradientView: UIView {

    override open class var layerClass: AnyClass {
        return CAGradientLayer.classForCoder()
    }

    required public init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        configureGradientLayer()
    }

    public override init(frame: CGRect) {
        super.init(frame: frame)
        configureGradientLayer()
    }

    func configureGradientLayer() {
        let gradientLayer = layer as! CAGradientLayer
        gradientLayer.colors = [UIColor(hex: 0x003399).cgColor, UIColor(hex: 0x00297b).cgColor]
    }
}
Alexander Volkov
fuente
4
extension UIView {

    func applyGradient(isVertical: Bool, colorArray: [UIColor]) {
        if let sublayers = layer.sublayers {
            sublayers.filter({ $0 is CAGradientLayer }).forEach({ $0.removeFromSuperlayer() })
        }

        let gradientLayer = CAGradientLayer()
        gradientLayer.colors = colorArray.map({ $0.cgColor })
        if isVertical {
            //top to bottom
            gradientLayer.locations = [0.0, 1.0]
        } else {
            //left to right
            gradientLayer.startPoint = CGPoint(x: 0.0, y: 0.5)
            gradientLayer.endPoint = CGPoint(x: 1.0, y: 0.5)
        }

        backgroundColor = .clear
        gradientLayer.frame = bounds
        layer.insertSublayer(gradientLayer, at: 0)
    }

}

USO

someView.applyGradient(isVertical: true, colorArray: [.green, .blue])
Harris
fuente
3

Vista rápida simple basada en la versión de Yuchen

class GradientView: UIView {
    override class func layerClass() -> AnyClass { return CAGradientLayer.self }

    lazy var gradientLayer: CAGradientLayer = {
        return self.layer as! CAGradientLayer
    }()

    override init(frame: CGRect) {
        super.init(frame: frame)
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

}

Entonces puede usar gradientLayer después de la inicialización de esta manera ...

someView.gradientLayer.colors = [UIColor.whiteColor().CGColor, UIColor.blackColor().CGColor]
GregP
fuente
3

Mi solución es crear una UIViewsubclase con CAGradientLayeraccesible como propiedad de solo lectura. Esto le permitirá personalizar su gradiente como desee y no necesita manejar los cambios de diseño usted mismo. Implementación de subclase:

@interface GradientView : UIView

@property (nonatomic, readonly) CAGradientLayer *gradientLayer;

@end

@implementation GradientView

+ (Class)layerClass
{
    return [CAGradientLayer class];
}

- (CAGradientLayer *)gradientLayer
{
    return (CAGradientLayer *)self.layer;
}

@end

Uso:

self.iconBackground = [GradientView new];
[self.background addSubview:self.iconBackground];
self.iconBackground.gradientLayer.colors = @[(id)[UIColor blackColor].CGColor, (id)[UIColor whiteColor].CGColor];
self.iconBackground.gradientLayer.startPoint = CGPointMake(1.0f, 1.0f);
self.iconBackground.gradientLayer.endPoint = CGPointMake(0.0f, 0.0f);
Timur Bernikovich
fuente
3

Es una buena idea llamar a las soluciones anteriores para actualizar la capa en el

viewDidLayoutSubviews

para actualizar las vistas correctamente

Ronaldo Albertini
fuente
2

SWIFT 3

Para agregar una capa de degradado en su vista

  • Vincula tu punto de vista

    @IBOutlet var YOURVIEW : UIView!
  • Defina el CAGradientLayer ()

    var gradient = CAGradientLayer()
  • Aquí está el código que debe escribir en su vista

    YOURVIEW.layoutIfNeeded()

    gradient.startPoint = CGPoint(x: CGFloat(0), y: CGFloat(1)) gradient.endPoint = CGPoint(x: CGFloat(1), y: CGFloat(0)) gradient.frame = YOURVIEW.bounds gradient.colors = [UIColor.red.cgColor, UIColor.green.cgColor] gradient.colors = [ UIColor(red: 255.0/255.0, green: 56.0/255.0, blue: 224.0/255.0, alpha: 1.0).cgColor,UIColor(red: 86.0/255.0, green: 13.0/255.0, blue: 232.0/255.0, alpha: 1.0).cgColor,UIColor(red: 16.0/255.0, green: 173.0/255.0, blue: 245.0/255.0, alpha: 1.0).cgColor] gradient.locations = [0.0 ,0.6 ,1.0] YOURVIEW.layer.insertSublayer(gradient, at: 0)

Azharhussain Shaikh
fuente
1
Utilicé este enfoque, cambiando "vista superior" al nombre de mi IBoutlet para mi vista. Eliminé la línea "SearchView".
jessi
Buen plan: quizás también tenga en cuenta que puede usar cualquiera de las configuraciones de degradado. Por lo tanto, si comenta los colores degradados simples usando colores de interfaz de usuario con nombre, la imagen es la misma, pero si comenta el otro, el degradado de color depende del rojo al verde. Los usuarios pueden hacer cualquiera de los dos.
jessi
1

En Swift 3.1 he agregado esta extensión a UIView

import Foundation
import UIKit
import CoreGraphics


extension UIView {
    func gradientOfView(withColours: UIColor...) {

        var cgColours = [CGColor]()

        for colour in withColours {
            cgColours.append(colour.cgColor)
        }
        let grad = CAGradientLayer()
        grad.frame = self.bounds
        grad.colors = cgColours
        self.layer.insertSublayer(grad, at: 0)
    }
}

que luego llamo con

    class OverviewVC: UIViewController {

        override func viewDidLoad() {
            super.viewDidLoad()

            self.view.gradientOfView(withColours: UIColor.red,UIColor.green, UIColor.blue)

        }
}
iCyberPaul
fuente
0

He implementado esto en mi código.

UIView *view1 = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, self.view.frame.size.width, 31.0f)];
view1.backgroundColor = [UIColor clearColor];
CAGradientLayer *gradient = [CAGradientLayer layer];
gradient.frame = view1.bounds;
UIColor *topColor = [UIColor colorWithRed:132.0/255.0 green:222.0/255.0 blue:109.0/255.0 alpha:1.0];
UIColor *bottomColor = [UIColor colorWithRed:31.0/255.0 green:150.0/255.0 blue:99.0/255.0 alpha:1.0];
gradient.colors = [NSArray arrayWithObjects:(id)[topColor CGColor], (id)[bottomColor CGColor], nil];


[view1.layer insertSublayer:gradient atIndex:0];

Ahora puedo ver un gradiente en mi vista.

Padmaja
fuente
0

Para dar color degradado a UIView (swift 4.2)

func makeGradientLayer(`for` object : UIView, startPoint : CGPoint, endPoint : CGPoint, gradientColors : [Any]) -> CAGradientLayer {
        let gradient: CAGradientLayer = CAGradientLayer()
        gradient.colors = gradientColors
        gradient.locations = [0.0 , 1.0]
        gradient.startPoint = startPoint
        gradient.endPoint = endPoint
        gradient.frame = CGRect(x: 0, y: 0, w: object.frame.size.width, h: object.frame.size.height)
        return gradient
    }

Cómo utilizar

let start : CGPoint = CGPoint(x: 0.0, y: 1.0)
let end : CGPoint = CGPoint(x: 1.0, y: 1.0)

let gradient: CAGradientLayer = makeGradientLayer(for: cell, startPoint: start, endPoint: end, gradientColors: [
                    UIColor(red:0.92, green:0.07, blue:0.4, alpha:1).cgColor,
                    UIColor(red:0.93, green:0.11, blue:0.14, alpha:1).cgColor
                    ])

self.vwTemp.layer.insertSublayer(gradient, at: 0)
Hardik Thakkar
fuente