2015-03-17 17 views
13

Ho creato una barra di avanzamento da utilizzare in una tabellaView creando un gradiente. Funziona perfettamente.CALayer non ridimensionante con Autolayout

iPhone5: enter image description here

Per poter utilizzare l'applicazione su più dispositivi, io ho creato l'UIView in Storyboard, etichettato e vincoli aggiunto. Tuttavia, quando utilizzo l'app su un iPhone 6, il CALayer non viene ridimensionato.

iPhone6: enter image description here

trovo questo estremamente stupido, ma non importa. Mi sono guardato intorno e ho cercato di capire come risolvere questo per mesi, ma sono venuto fuori corto. ANYONE sa come ridimensionare i CALayer con UIView? Qualsiasi aiuto sarebbe molto apprezzato! Grazie.

 progressBar = cell.contentView.viewWithTag(3) as UIView! 
     progressBar.layer.cornerRadius = 4 
     progressBar.layer.masksToBounds = true 


     // create gradient layer 
     let gradient : CAGradientLayer = CAGradientLayer() 

     // create color array 
     let arrayColors: [AnyObject] = [ 
      UIColor (red: 255/255, green: 138/255, blue: 1/255, alpha: 1).CGColor, 
      UIColor (red: 110/255, green: 110/255, blue: 118/255, alpha: 1).CGColor] 

     // set gradient frame bounds to match progressBar bounds 
     gradient.frame = progressBar.bounds 

     // set gradient's color array 
     gradient.colors = arrayColors 

     //Set progress(progressBar) 
     var percentageCompleted = 0.6 

     gradient.startPoint = CGPoint(x: 0.0, y: 0.5) 
     gradient.locations = [percentageCompleted, percentageCompleted] 
     gradient.endPoint = CGPoint(x: 1, y: 0.5) 

     // replace base layer with gradient layer 
     progressBar.layer.insertSublayer(gradient, atIndex: 0) 

risposta

44

Lo strato di default di un UIView non ridimensionare con la sua vista, ma sottolivelli non lo fanno (come hai scoperto). Un modo per farlo funzionare è creare una classe di visualizzazione personalizzata, spostare il codice che hai nella tua domanda e sovrascrivere layoutSublayersOfLayer in cui puoi impostare il gradiente in modo che abbia le stesse dimensioni della vista. Poiché questo codice è ora in una classe personalizzata, ho anche creato una proprietà percentualeCompletata (anziché una variabile locale) e ho aggiunto una clausola willSet in modo che l'aspetto della barra venga aggiornato ogni volta che si modifica la proprietà percentualeCompletata.

class RDProgressView: UIView { 

    private let gradient : CAGradientLayer = CAGradientLayer() 

    var percentageCompleted: Double = 0.0 { 
     willSet{ 
      gradient.locations = [newValue, newValue] 
     } 
    } 

    override func awakeFromNib() { 
     self.layer.cornerRadius = 4 
     self.layer.masksToBounds = true 

     // create color array 
     let arrayColors: [AnyObject] = [ 
      UIColor (red: 255/255, green: 138/255, blue: 1/255, alpha: 1).CGColor, 
      UIColor (red: 110/255, green: 110/255, blue: 118/255, alpha: 1).CGColor] 

     // set gradient's color array 
     gradient.colors = arrayColors 

     //Set progress(progressBar) 
     gradient.startPoint = CGPoint(x: 0.0, y: 0.5) 
     gradient.locations = [percentageCompleted, percentageCompleted] 
     gradient.endPoint = CGPoint(x: 1, y: 0.5) 

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

    override func layoutSublayersOfLayer(layer: CALayer!) { 
     super.layoutSublayersOfLayer(layer) 
     gradient.frame = self.bounds 
    } 
} 

In IB, si dovrebbe modificare la classe di immagine per RDProgressView (nel mio esempio), in cellForRowAtIndexPath, si avrebbe solo bisogno di ottenere un riferimento alla vista, e impostare la proprietà percentageCompleted.

progressBar = cell.contentView.viewWithTag(3) as RDProgressView! 
progressBar.percentageCompleted = 0.2 
+0

Grazie mille - funziona perfettamente. La tua risposta è completa, la soluzione elegante e ha risolto il mio problema. Oggi apprenderò su awakeFromNib e willSet. Grazie ancora! (Oh e ho frastagliata prima e l'ultima riga del primo blocco di codice e un'istanza ProgressBar con l'aggiunta di lasciare) – KML

11

In alternativa la risposta accettata, si potrebbe anche cambiare la classe strato di vista di essere CAGradientLayer. Il livello delle viste verrà sempre ridimensionato in base alle modifiche del layout. È possibile ottenere che sottoclasse UIView

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

quindi impostare i colori

if let gradientLayer = gradientView.layer as? CAGradientLayer { 
    gradientLayer.colors = arrayColors 
} 

E 'meno codice di aggiunta e il mantenimento di un sottolivello, ma potrebbe non soddisfare tutti i casi d'uso.

+0

override di classe var layerClass: AnyClass { ritorno CAGradientLayer.self } di override var strato: CAGradientLayer {super.layer ritorno come! CAGradientLayer } – lastcc

+0

Molto più pulito. Potresti nominare uno dei casi d'uso che ritieni che questo approccio potrebbe non essere adatto? – keeshux

Problemi correlati