2015-03-17 20 views
13

Ich habe einen Fortschrittsbalken erstellt, der in einer TableView verwendet werden soll, indem ein Gradient Layer erstellt wird. Es funktioniert perfekt.CALayer ändert nicht mit Autolayout

iPhone5: enter image description here

Um die App auf mehreren Geräten zu verwenden, die ich geschaffen habe die UIView in der Storyboard, markiert sie und fügte hinzu Einschränkungen. Wenn ich jedoch die App auf einem iPhone 6 verwende, ändert sich der CALayer nicht.

iPhone6: enter image description here

Ich finde das sehr dumm, aber nie Geist. Ich habe mich umgesehen und versucht zu verstehen, wie ich das für Monate lösen kann, aber ich bin kurz gekommen. Ist ANYONE wissen, wie man CALayers Größe mit der UIView machen? Jede Hilfe würde sehr geschätzt werden! Vielen Dank.

 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) 

Antwort

44

Die Standardschicht eines UIView mit Blick nicht die Größe, sondern Subschichten nicht (wie Sie herausgefunden). Eine Möglichkeit, dies zu erreichen, besteht darin, eine benutzerdefinierte Ansichtsklasse zu erstellen, den Code, der in Ihrer Frage enthalten ist, zu überschreiben und layoutSublayersOfLayer zu überschreiben, wobei Sie die Gradient-Ebene auf dieselbe Größe wie die Ansicht festlegen können. Da dieser Code jetzt in einer benutzerdefinierten Klasse enthalten ist, habe ich auch eine propertyCompleted-Eigenschaft (anstelle einer lokalen Variablen) erstellt und eine willSet-Klausel hinzugefügt, sodass die Darstellung der Leiste jedes Mal aktualisiert wird, wenn Sie die percentageCompleted-Eigenschaft ändern.

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, würden Sie die Klasse Ihrer Ansicht nach RDProgressView ändern (in meinem Beispiel), und in cellForRowAtIndexPath, müssten Sie nur einen Verweis auf die Ansicht zu erhalten, und legen Sie seine percentageCompleted Eigenschaft.

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

Vielen Dank - es funktioniert perfekt. Sie antworten, ist abgeschlossen, die Lösung elegant und es hat mein Problem gelöst. Heute werde ich über watchFromNib und willSet lernen. Danke nochmal! (OH und I eingekerbt erste und letzte Zeile des ersten Blocks von Code und instanziiert progressBar durch Zugabe ließ) – KML

11

Als Alternative zu der akzeptierten Antwort, könnten Sie auch die Ansichten Schichtklasse ändern CAGradientLayer zu sein. Der Sichtenlayout wird immer entsprechend den Layoutänderungen angepasst. Sie können das erreichen, indem UIView Subklassen

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

legen Sie dann die Farben

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

Es weniger Code ist als das Hinzufügen und eine Unterschicht beibehalten, aber möglicherweise nicht alle Anwendungsfälle anpassen.

+0

Überschreibung Klasse var layerClass: AnyClass { return CAGradientLayer.self } Überschreibung var Schicht: CAGradientLayer { return super.layer wie! CAGradientLayer } – lastcc

+0

Viel sauberer. Können Sie einen der Anwendungsfälle benennen, die Ihrer Meinung nach diesem Ansatz nicht entsprechen? – keeshux