Creare a livello di programmazione una vista UIV con sfumatura di colore


Risposte:


694

Objective-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];

Swift:

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)

Informazioni : utilizzare startPoint ed endPoint per cambiare la direzione del gradiente .

Se ci sono altre viste aggiunte su questo UIView(come una UILabel), potresti prendere in considerazione l'idea di impostare il colore di sfondo di quelle UIViewin [UIColor clearColor]modo che la vista sfumata sia presentata al posto del colore di sfondo per le viste secondarie. L'utilizzo clearColorha un leggero impatto sulle prestazioni.


13
+1 per la quantità più breve di codice tra tutte le soluzioni. Ho appena aggiunto al mio controller di visualizzazione esistente, ho cambiato i 2 riferimenti viewin self.viewe ha funzionato come un fascino :)
Ergin

4
Anche rilevante è dove aggiungere questo codice. Avevo bisogno del seguente post per farlo funzionare: stackoverflow.com/a/20059268/1480518
Garrett Disco

13
Questo mi ha aiutato molto! Ho perso la parte CGColor ovunque! Grazie
Gyfis,

48
Non dimenticare di usare 'startPoint' e 'endPoint' per cambiare la direzione del gradiente. I valori predefiniti sono (0,5, 0) e (0,5,1), dall'alto verso il basso.
Valentin Shamardin,

12
Quando il mio UIView sta usando AutoLayout, ho anche dovuto chiamare gradient.frame = view.boundsin viewDidAppear()e didRotateFromInterfaceOrientation()altrimenti il gradiente non essere dimensionato in modo corretto.
EricRobertBrewer

70

È possibile creare una classe personalizzata 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]
    }
}

Nello storyboard, imposta il tipo di classe su qualsiasi vista che desideri avere uno sfondo sfumato:

inserisci qui la descrizione dell'immagine

Questo è meglio nei seguenti modi:

  • Non è necessario impostare il frame di CLayer
  • Utilizzare NSConstraintcome al solito sulUIView
  • Non è necessario creare sublayer (meno utilizzo della memoria)

1
Su Swift 3 layerClassnon è più una funzione, è una proprietà, quindi devi sovrascriverla come una proprietà: stackoverflow.com/questions/28786597/… . Inoltre devi implementare override init(frame: CGRect), controlla questa risposta: stackoverflow.com/questions/27374330/… . Grazie!
LaloLoop,

Ciao @LaloLoop, grazie per il commento! Ho aggiornato il codice. Non penso di dover scavalcare init(frame:CGRect)però. Ho testato il codice aggiornato e funziona benissimo.
Yuchen Zhong

@Yuchen Zhong Si blocca in IB, ma funziona nell'app. Qualche motivo per cui non viene eseguito il rendering in IB se @IBDesignableviene utilizzato?
Alexander Volkov

@AlexanderVolkov Probabilmente qualche altro problema? Lo abbiamo usato così nello storyboard e non sembra avere alcun problema. Puoi eseguire il debug dello storyboard e vedere quale linea lo sta bloccando.
Yuchen Zhong,

1
Soluzione migliore !
Baran Emre,

40

Prova questo ha funzionato come un incanto per me,

Obiettivo C

Ho impostato il colore di sfondo sfumato RGB su 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];

inserisci qui la descrizione dell'immagine

AGGIORNATO: - Swift3 +

Codice : -

 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)

inserisci qui la descrizione dell'immagine

È possibile aggiungere il punto iniziale e finale del colore sfumato.

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

inserisci qui la descrizione dell'immagine

Per maggiori dettagli descrizione fare riferimento a CAGradientLayer Doc

Spero che questo sia di aiuto per qualcuno.


36

Questo è il mio approccio raccomandato.

Per promuovere la riusabilità, direi di creare una categoria di CAGradientLayere aggiungere i gradienti desiderati come metodi di classe. Specificali nel headerfile in questo modo:

#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

Quindi nel tuo file di implementazione, specifica ogni sfumatura con questa sintassi:

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

Quindi importa semplicemente questa categoria nella tua ViewControllero in qualsiasi altra richiesta subclasse usala in questo modo:

CAGradientLayer *backgroundLayer = [CAGradientLayer purpleGradientLayer];
backgroundLayer.frame = self.view.frame;
[self.view.layer insertSublayer:backgroundLayer atIndex:0];

dove dovresti mettere il codice per usarlo? quale metodo del ciclo di vita? viewdidappear lo fa apparire un secondo troppo tardi. viewdidload e viewdidappear non funzionano durante la rotazione. viewdidlayoutsubviews funziona meglio per la rotazione ma finisce per sembrare un po 'instabile.
Adam Johns,

L'ho inserito personalmenteviewDidLoad
Sam Fischer il

1
Quando l'ho inserito viewDidLoad, non funzionava se l'app veniva avviata con orientamento orizzontale. La mia soluzione era quella di rendere la cornice del livello di sfondo più ampia della view.frame per compensare altri orientamenti.
Adam Johns,

2
viewDidLoad funziona, devi solo impostare AutoResizingMask usando [backgroundLayer setAutoresizingMask: UIViewAutoresizingFLEXWidth | UIViewAutoresizingFLEXHeight];
ekscrypto

21

Dato che avevo bisogno di un solo tipo di gradiente in tutta la mia app, ho creato una sottoclasse di UIView e ho preconfigurato il livello gradiente all'inizializzazione con colori fissi. Gli inizializzatori di UIView chiamano configureGradientLayer -method, che 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

Il nome del metodo initGradientLayerè simile a un inizializzatore. Non penso sia molto adatto.
DawnSong,

@DawnSong Buon punto, l'ho cambiato in 'configureGradientLayer'.
Blauzahn,

12

Implementazione rapida:

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)

11

Ho esteso un po 'la risposta accettata usando la funzionalità di estensione di Swift e un enum.

Oh, e se si utilizza Storyboard come faccio io, assicuratevi di chiamare gradientBackground(from:to:direction:)in viewDidLayoutSubviews()o successiva.

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

10

L'ho implementato rapidamente con un'estensione:

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, posso impostare una sfumatura su ogni vista in questo modo:

myImageView.addGradientWithColor(UIColor.blue)

La chiamata Swift3 deve essere simile a: myImageView.addGradientWithColor (color: UIColor.blue)
mgyky

8

Un approccio rapido

Questa risposta si basa sulle risposte sopra e fornisce l'implementazione per affrontare il problema del gradiente che non viene applicato correttamente durante la rotazione. Soddisfa questo problema modificando il livello gradiente in un quadrato in modo che la rotazione in tutte le direzioni dia luogo a un gradiente corretto. La firma della funzione include un argomento variadico Swift che consente di passare tutti i CGColorRef (CGColor) necessari (vedere utilizzo di esempio). Viene fornito anche un esempio come estensione Swift in modo da poter applicare un gradiente a qualsiasi 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)
    }

Usare:

in viewDidLoad ...

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

Implementazione dell'estensione

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

}

Esempio di caso d'uso di estensione:

 override func viewDidLoad() {
        super.viewDidLoad()

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

Ciò significa che lo sfondo sfumato può ora essere applicato a qualsiasi UIControl poiché tutti i controlli sono UIVview (o una sottoclasse) e tutte le UIVview hanno CALayer.

Swift 4

Implementazione dell'estensione

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

Esempio di caso d'uso di estensione:

override func viewDidLoad() {
    super.viewDidLoad()

    self.view.layer.configureGradientBackground(UIColor.purple.cgColor, UIColor.blue.cgColor, UIColor.white.cgColor)
}

5

Quello che stai cercando è CAGradientLayer. Ognuno UIViewha un layer: in quel layer puoi aggiungere sublayer, così come puoi aggiungere subview. Un tipo specifico è il CAGradientLayer, dove gli dai una gamma di colori tra cui sfumare.

Un esempio è questo semplice wrapper per una vista a gradiente:

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

Si noti che è necessario includere il framework QuartZCore per accedere a tutte le parti di layer di una UIView.


4

Swift 4:

Mostra correttamente il gradiente in IB:

@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]
    }
}

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

3

Vista rapida semplice basata sulla versione di 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)
    }

}

Quindi è possibile utilizzare gradientLayer dopo l'inizializzazione in questo modo ...

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

3

La mia soluzione è creare una UIViewsottoclasse con CAGradientLayeraccessibile come proprietà di sola lettura. Ciò ti consentirà di personalizzare il gradiente come desideri e di non dover gestire autonomamente le modifiche al layout. Implementazione della sottoclasse:

@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);

3

È una buona idea chiamare le soluzioni sopra per aggiornare il layer su

viewDidLayoutSubviews

per ottenere le viste aggiornate correttamente


2

SWIFT 3

Per aggiungere un livello sfumato alla vista

  • Associa il tuo punto di vista

    @IBOutlet var YOURVIEW : UIView!
  • Definire CAGradientLayer ()

    var gradient = CAGradientLayer()
  • Ecco il codice che devi scrivere nel tuo 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)


1
Ho usato questo approccio, cambiando "topview" con il nome del mio IBoutlet per la mia vista. Ho eliminato la riga "SearchView".
jessi,

Buon piano - forse nota anche che puoi usare una delle configurazioni gradiente.colori. Quindi, se commentate i semplici gradiente.colori usando i colori dell'interfaccia utente denominati, l'immagine è la stessa, ma se commentate l'altro, il gradiente di colore si basa sul rosso sul verde. Gli utenti possono fare uno dei due.
jessi,

1

In Swift 3.1 ho aggiunto questa estensione 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)
    }
}

con cui poi chiamo

    class OverviewVC: UIViewController {

        override func viewDidLoad() {
            super.viewDidLoad()

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

        }
}

0

Ho implementato questo nel mio codice.

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];

Ora posso vedere una sfumatura nella mia vista.


0

Per dare un colore sfumato a UIView (rapido 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
    }

Come usare

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)
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.