Crie programaticamente um UIView com gradiente de cores

Respostas:

694

Objetivo-C:

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)

Informações : use startPoint e endPoint para alterar a direção do gradiente .

Se houver outras visualizações adicionadas a isso UIView(como a UILabel), convém definir a cor de plano de fundo daquelas UIViewpara [UIColor clearColor]que a visualização de gradiente seja apresentada em vez da cor de segundo plano para as sub-visualizações. O uso clearColortem um leve impacto no desempenho.

Arslan Ali
fonte
13
+1 para a menor quantidade de código dentre todas as soluções. Eu só acrescentou ao meu controlador de vista existente, mudou os 2 refs para viewa self.viewe funcionou como um encanto :)
Ergin
4
Também relevante é onde adicionar esse código. Eu precisava da seguinte postagem para fazer isso funcionar: stackoverflow.com/a/20059268/1480518
Garrett Disco
13
Isso me ajudou muito! Perdeu a parte CGColor em qualquer outro lugar! Obrigado
Gyfis
48
Não se esqueça de usar 'startPoint' e 'endPoint' para alterar a direção do gradiente. Os valores padrão são (0,5, 0) e (0,5,1) - da direção superior para a inferior.
Valentin Shamardin
12
Quando meu UIView está usando AutoLayout, eu também tive que chamar gradient.frame = view.boundsem viewDidAppear()e em didRotateFromInterfaceOrientation(), ou então o gradiente de não ser dimensionado corretamente.
EricRobertBrewer
70

Você pode criar uma classe 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]
    }
}

No storyboard, defina o tipo de classe para qualquer visualização em que você queira ter um fundo gradiente:

insira a descrição da imagem aqui

Isso é melhor das seguintes maneiras:

  • Não é necessário definir o quadro de CLayer
  • Use NSConstraintnormalmente noUIView
  • Não é necessário criar subcamadas (menos uso de memória)
Yuchen Zhong
fonte
1
No Swift 3, layerClassnão é mais uma função, é uma propriedade, portanto você deve substituí-la como uma propriedade: stackoverflow.com/questions/28786597/… . Além disso, você deve implementar override init(frame: CGRect), verifique esta resposta: stackoverflow.com/questions/27374330/… . Obrigado!
LaloLoop 19/09/16
Olá @LaloLoop, obrigado pelo comentário! Eu atualizei o código. Acho que não tenho que substituir init(frame:CGRect). Testei o código atualizado e funciona bem.
Yuchen Zhong
@Yuchen Zhong Ele falha no IB, mas funciona no aplicativo. Algum motivo pelo qual não é renderizado no IB se @IBDesignablefor usado?
Alexander Volkov
@AlexanderVolkov Provavelmente alguma outra questão? Nós o usamos dessa forma no storyboard e, no entanto, não parece ter nenhum problema. Você pode depurar seu storyboard e ver qual linha está travando.
Yuchen Zhong
1
Melhor solução !
Baran Emre
40

Tente isso, funcionou como um encanto para mim,

Objetivo C

Eu configurei Cor de fundo gradiente RGB para 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];

insira a descrição da imagem aqui

ATUALIZADO: - 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)

insira a descrição da imagem aqui

Você pode adicionar o ponto inicial e final da cor gradiente.

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

insira a descrição da imagem aqui

Para uma descrição mais detalhada, consulte CAGradientLayer Doc

Espero que isso ajude alguém.

Jaywant Khedkar
fonte
36

Esta é a minha abordagem recomendada.

Para promover a reutilização, eu diria que crie uma categoria CAGradientLayere adicione os gradientes desejados como métodos de classe. Especifique-os no headerarquivo como este:

#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

Em seu arquivo de implementação, especifique cada gradiente com esta sintaxe:

+ (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;
}

Em seguida, basta importar esta categoria para o seu ViewControllerou qualquer outro requerido subclasse usá-lo assim:

CAGradientLayer *backgroundLayer = [CAGradientLayer purpleGradientLayer];
backgroundLayer.frame = self.view.frame;
[self.view.layer insertSublayer:backgroundLayer atIndex:0];
Sam Fischer
fonte
onde você deve colocar o código para usá-lo? que método de ciclo de vida? viewdidappear faz parecer um segundo tarde demais. viewdidload e viewdidappear fazem com que ele não funcione durante a rotação. viewdidlayoutsubviews funciona melhor para rotação, mas ainda parece um pouco instável.
Adam Johns
Pessoalmente, colocá-lo em:viewDidLoad
Sam Fischer
1
Quando o coloquei viewDidLoad, ele não funcionaria se o aplicativo fosse iniciado na orientação paisagem. Minha solução foi tornar o quadro da camada de fundo mais amplo que o view.frame para compensar outras orientações.
Adam Johns
2
viewDidLoad funciona, você também precisa definir o AutoResizingMask usando [backgroundLayer setAutoresizingMask: UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight];
ekscrypto
21

Como eu só precisava de um tipo de gradiente em todo o meu aplicativo, criei uma subclasse do UIView e pré-configurei a camada de gradiente na inicialização com cores fixas. Os inicializadores do UIView chamam o método configureGradientLayer , que configura o 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
fonte
O nome do método initGradientLayeré semelhante a um inicializador. Eu não acho muito apropriado.
precisa saber é o seguinte
@DawnSong Bom ponto, mudei para 'configureGradientLayer'.
precisa saber é o seguinte
12

Implementação 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
fonte
11

Estendi a resposta aceita um pouco, usando a funcionalidade de extensão do Swift, bem como uma enumeração.

Ah, e se você estiver usando Storyboard como eu, certifique-se chamar gradientBackground(from:to:direction:)em viewDidLayoutSubviews()ou depois.

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
fonte
10

Eu implementei isso rapidamente com uma extensão:

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)
    }
}

Não, eu posso definir um gradiente em todas as visualizações como esta:

myImageView.addGradientWithColor(UIColor.blue)
patrickS
fonte
A chamada Swift3 deve ser como: myImageView.addGradientWithColor (color: UIColor.blue)
mgyky
8

Uma abordagem rápida

Esta resposta se baseia nas respostas acima e fornece implementação para lidar com o problema do gradiente não ser aplicado corretamente durante a rotação. Satisfaz esse problema alterando a camada de gradiente para um quadrado, para que a rotação em todas as direções resulte em um gradiente correto. A assinatura da função inclui um argumento variável Swift que permite a passagem de tantos CGColorRef (CGColor) quanto necessário (consulte o uso de amostra). Também é fornecido um exemplo como uma extensão Swift, para que se possa aplicar um gradiente a qualquer 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:

em viewDidLoad ...

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

Implementação de extensão

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)
    }

}

Exemplo de caso de uso de extensão:

 override func viewDidLoad() {
        super.viewDidLoad()

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

O que significa que o fundo gradiente agora pode ser aplicado a qualquer UIControl, pois todos os controles são UIViews (ou uma subclasse) e todos os UIViews possuem CALayers.

Swift 4

Implementação de extensão

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)
    }    
}

Exemplo de caso de uso de extensão:

override func viewDidLoad() {
    super.viewDidLoad()

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

O que você está procurando é CAGradientLayer. Todo mundo UIViewtem uma camada - nessa camada, você pode adicionar subcamadas, assim como adicionar subviews. Um tipo específico é o CAGradientLayer, no qual você fornece uma variedade de cores para diferenciar.

Um exemplo é este wrapper simples para uma visualização de gradiente:

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

Observe que você precisa incluir a estrutura QuartZCore para acessar todas as partes da camada de um UIView.

Kendall Helmstetter Gelner
fonte
4

Swift 4:

Mostra gradiente no IB corretamente:

@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
fonte
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
fonte
3

Visualização rápida simples com base na versão 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)
    }

}

Então você pode usar gradientLayer após a inicialização como esta ...

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

Minha solução é criar UIViewsubclasse CAGradientLayeracessível como uma propriedade somente leitura. Isso permitirá que você personalize seu gradiente da maneira que desejar e não precisará lidar com as alterações de layout. Implementação de subclasse:

@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
fonte
3

É uma boa ideia chamar as soluções acima para atualizar a camada no

viewDidLayoutSubviews

para atualizar as visualizações corretamente

Ronaldo Albertini
fonte
2

SWIFT 3

Para adicionar uma camada de gradiente à sua visualização

  • Vincule seu ponto de vista

    @IBOutlet var YOURVIEW : UIView!
  • Definir o CAGradientLayer ()

    var gradient = CAGradientLayer()
  • Aqui está o código que você deve escrever na sua viewDidLoad

    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
fonte
1
Eu usei essa abordagem, alterando "topview" para o nome do meu IBoutlet para minha visão. Eu apaguei a linha "SearchView".
jessi
Bom plano - talvez também note que você pode usar qualquer uma das configurações de gradient.colors. Portanto, se você comentar as cores simples gradient.colours usando cores nomeadas da interface do usuário, a imagem será a mesma, mas se você comentar a outra, o gradiente de cores dependerá do vermelho para o verde. Os usuários podem fazer qualquer um.
jessi
1

No Swift 3.1, adicionei esta extensão ao 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 eu chamo com

    class OverviewVC: UIViewController {

        override func viewDidLoad() {
            super.viewDidLoad()

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

        }
}
iCyberPaul
fonte
0

Eu implementei isso no meu 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];

Agora eu posso ver um gradiente na minha visão.

Padmaja
fonte
0

Para dar cor de gradiente ao 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
    }

Como usar

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
fonte