2016-02-03 13 views
21

nicht laden Ich habe eine xib (childXib) Datei, die mit seiner benutzerdefinierten UIView Swift-Datei über seine Owner verknüpft ist. DieseKonnte IBDesignable Xib im Interface Builder

ist, wie ich meine benutzerdefinierte initialisieren UIView:

// init for IBDesignable 
override init(frame: CGRect) { 
    super.init(frame: frame) 

    let view = loadViewFromNib() 
    view.frame = bounds 

    addSubview(view) 
} 

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

func loadViewFromNib() -> UIView { 

    let bundle = NSBundle(forClass: self.dynamicType) 
    let nib = UINib(nibName: "CommentCellView", bundle: bundle) 
    let view = nib.instantiateWithOwner(self, options: nil)[0] as! UIView 

    return view 
} 

Als ich dieses xib (childXib) in einem anderen xib (parentXib) hinzufügen möchten, habe ich die folgenden Fehlermeldungen erhalten:

error: IB Designables: Failed to render instance of MyRootView: The agent threw an exception. 

Wobei MyRootView die Datei ist, die mit parentXib

verknüpft ist

Dabei ist MyIBDesignableCustomViewFilename die Datei, die mit childXib verknüpft ist.

Wenn ich es debuggen, indem Debug in Custom class vom Identity inspector auf klicken, ist es nicht von dieser Linie zu arbeiten:

let view = nib.instantiateWithOwner(self, options: nil)[0] as! UIView 

Alle xib Dateien sind in Copy Bundle Resources in Build Phases.

Irgendeine Idee, was ist los?

+0

Hat Ihr xib eine Unterklasse UIView verwenden? Wenn dies der Fall ist, möchten Sie vielleicht versuchen, es in diese Klasse zu übertragen. – AMayes

+0

Ja, sie sind alle Unterklassen von 'UIView' – Nico

+0

Dann versuchen Sie' Let View = nib.instantiateWithOwner (self, Optionen: nil) [0] as! MyCustomView' – AMayes

Antwort

0

Für beide Fehler wie unten:

error: IB Designables: Failed to render instance of .... 
error: IB Designables: Failed to update auto layout status: The agent raised a "NSInternalInconsistencyException" exception: Could not load NIB in bundle ... 

Ich schlage vor, eine kleine schnelle Selbstüberprüfung zu haben, kann helfen, herauszufinden, wo die Probleme angegangen werden sollten:

  1. Überprüfen Sie, ob .xib Dateien in einem Projekt korrekt hinzugefügt
  2. Überprüfen Sie, ob nibName richtig eingestellt ist, manchmal Tippfehler passiert hier
  3. Überprüfen Sie, ob beide Ausgang & Aktion sind in geeigneter Weise verbinden, umfassen Codes Implementierung
14

Erster Schritt:

Ich gebe Ihnen eine Einführung in IBDesignable und IBInspectable und zeigen euch, wie die Vorteile der neuen Funktion zu übernehmen. Es gibt keinen besseren Weg, ein Feature zu entwickeln, als eine Demo zu erstellen. Also werden wir eine benutzerdefinierte Schnittstelle namens "Rainbow" zusammen bauen.

IBDesignable und IBInspectable

Mit IBDesignable und IBInspectable sind Entwickler erlaubt Schnittstelle zu erstellen (oder Ansicht), die in Echtzeit im Interface Builder macht. Um diese neue Funktion anzuwenden, müssen Sie lediglich eine visuelle Klasse erstellen, indem Sie UIView oder UIControl ableiten und dann den Klassennamen in Swift mit dem @IBDesignable-Schlüsselwort voranstellen. Wenn Sie Objective-C verwenden, verwenden Sie stattdessen das Makro IB_DESIGNABLE.Hier ist ein Beispielcode in Swift:

@IBDesignable 
class Rainbow: UIView { 
} 

In älteren Versionen von Xcode, können Sie die benutzerdefinierte Laufzeit bearbeiten Attribute Eigenschaften eines Objekts ändern (zum Beispiel layer.cornerRadius) im Interface Builder. Das Problem ist, dass Sie den genauen Namen der Eigenschaften eingeben müssen. IBInspectable macht einen Schritt vorwärts. Wenn Sie eine Eigenschaft der visuellen Klasse mit IBInspectable Präfix, wird die Eigenschaft auf das Interface Builder ausgesetzt werden, so dass Sie ihren Wert in eine viel einfachen Art und Weise ändern können:

enter image description here

Auch wenn Sie Ihre Anwendung entwickeln In Swift müssen Sie der ausgewählten Eigenschaft lediglich das Schlüsselwort @IBInspectable voranstellen. Hier ist ein Beispiel-Code-Snippet:

@IBInspectable var firstColor: UIColor = UIColor.blackColor() 
{ 
    // Update your UI when value changes 
} 



@IBInspectable var firstColor: UIColor = UIColor.blackColor() 
{ 
    // Update your UI when value changes 
} 

Bauen Sie Ihre Xcode Projekt

Lassen Sie uns beginnen, indem Sie ein neues Projekt in Xcode erstellen und Single View Anwendung als Vorlage auswählen, und nennen Sie es RainbowDemo. Wir werden Swift in diesem Projekt als Programmiersprache verwenden, also vergiss nicht, es beim Erstellen des Projekts zu wählen.

Sobald Sie fertig sind, wählen Sie die Main.storyboard im Projektnavigator und ziehen Sie ein View-Objekt aus der Objektbibliothek auf den View Controller. Ändern Sie die Farbe in # 38334C (oder in der von Ihnen gewünschten Farbe) und stellen Sie die Größe auf 600 mal 434 ein. Stellen Sie sie dann in die Mitte der Hauptansicht. Vergessen Sie nicht, die Farbe der Hauptansicht in die gleiche Farbe des Ansichtsobjekts zu ändern. Tipp: Wenn Sie die RGB-Farbwerte für Ihren Code ändern möchten, öffnen Sie einfach Ihre Farbpalette und wechseln Sie zur Registerkarte Schieberegler, um die RGB-Werte zu ändern.

Verwirrt werden? Keine Bange. Sie werden verstehen, was ich meine, nachdem ich die Projektdemo durchgegangen bin.

Mit Xcode 6 müssen Sie automatische Layoutbeschränkungen für die Ansicht konfigurieren, um alle Arten von iOS-Geräten zu unterstützen. Auto-Layout ist in der neuesten Version von Xcode ziemlich mächtig. Für einfache Einschränkungen können Sie einfach auf die Option Issues im Menü Auto-Layout klicken und "Fehlende Contracts hinzufügen" wählen, und Xcode wird automatisch die Layout-Constraints für die Ansicht konfigurieren.

enter image description here

Erstellen von benutzerdefinierter Ansicht Klasse

Nun, da Sie die Ansicht im Storyboard erstellt haben, ist es Zeit, unsere eigene Ansichtsklasse zu erstellen. Wir verwenden die Swift-Klassenvorlage für die Klassenerstellung. Nennen Sie es "Regenbogen".

enter image description here

Then insert the following code in the class: 

import UIKit 

class Rainbow: UIView { 
    required init(coder aDecoder: NSCoder) { 
     super.init(coder: aDecoder) 
    } 

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

Wie bereits erwähnt, ist die visuelle Klasse eine Unterklasse von UIView. Um unsere benutzerdefinierte Klasse im Live-Rendering zu verwenden, müssen wir beide Initialisierer wie oben gezeigt überschreiben. Weiter teilen die Ansicht durch den Assistenten-Editor auswählen:

enter image description here

Sobald das Hauptstoryboard im Assistenten-Editor gemacht, wählen, so können Sie sehen, was Sie in Echtzeit aufbauen.Denken Sie daran, die Klassennamen der Ansicht zu „Rainbow“ unter der Identität Inspektoren zu ändern:

Implementierung IBDesignable Steuert

Der erste Schritt eine Steuerung für die Live-Wiedergabe zu ermöglichen, ist die benutzerdefinierte Ansicht als Gestaltbare zu setzen, indem den Klassennamen mit @IBDesignable prefixing:

@IBDesignable 
class Rainbow: UIView { 
    ... 
} 

Es ist ein bisschen einfach, wie man sehen kann. Aber dieses einfache Keyword würde Ihre Entwicklung viel einfacher machen. Als Nächstes fügen wir einige Eigenschaften hinzu, um die Farben der Kreise festzulegen. Fügen Sie diese Zeilen Code in der Regenbogen-Klasse:

@IBInspectable var firstColor: UIColor = UIColor(red: (37.0/255.0), green: (252.0/255), blue: (244.0/255.0), alpha: 1.0) 
@IBInspectable var secondColor: UIColor = UIColor(red: (171.0/255.0), green: (250.0/255), blue: (81.0/255.0), alpha: 1.0) 
@IBInspectable var thirdColor: UIColor = UIColor(red: (238.0/255.0), green: (32.0/255) 

Hier stellen wir jede Eigenschaft mit einer Standardfarbe vordefinieren, und melden Sie es der Ansicht, jedes Mal, wenn ein Benutzer ändert seinen Wert neu zu zeichnen. Am wichtigsten ist, dass wir jeder Eigenschaft das @ IBInspectable-Schlüsselwort voranstellen. Wenn Sie zu den inspizierbaren Attributen der Ansicht gehen, sollten Sie diese Eigenschaften visuell finden:

Cool, oder? Indem Sie die Eigenschaften als IBInspectable angeben, können Sie sie visuell mithilfe der Farbauswahl bearbeiten.

Okay, lasst uns die wichtigsten Methoden der Rainbow-Klasse implementieren, mit der ein Kreis auf dem Bildschirm gezeichnet wird. Fügen Sie die folgende Methode in der Klasse:

func addOval(lineWidth: CGFloat, path: CGPathRef, strokeStart: CGFloat, strokeEnd: CGFloat, strokeColor: UIColor, fillColor: UIColor, shadowRadius: CGFloat, shadowOpacity: Float, shadowOffsset: CGSize) { 

    let arc = CAShapeLayer() 
    arc.lineWidth = lineWidth 
    arc.path = path 
    arc.strokeStart = strokeStart 
    arc.strokeEnd = strokeEnd 
    arc.strokeColor = strokeColor.CGColor 
    arc.fillColor = fillColor.CGColor 
    arc.shadowColor = UIColor.blackColor().CGColor 
    arc.shadowRadius = shadowRadius 
    arc.shadowOpacity = shadowOpacity 
    arc.shadowOffset = shadowOffsset 
    layer.addSublayer(arc) 
} 

enter image description here

Um den Code sauber und lesbar zu machen, schaffen wir eine gemeinsame Methode einen Voll- oder Halbkreis zum Zeichnen nach den vom Anrufer angegebenen Parameter. Es ist ziemlich einfach, mit der CAShapeLayer-Klasse einen Kreis oder einen Bogen zu zeichnen. Sie können den Start und das Ende des Stokes mithilfe der Eigenschaften strokeStart und strokeEnd steuern. Indem Sie den Wert von stokeEnd zwischen 0,0 und 1,0 variieren, können Sie einen vollständigen oder teilweisen Kreis zeichnen. Der Rest der Eigenschaften wird nur verwendet, um die Farbe eines Strichs, einer Schattenfarbe usw. festzulegen. In der offiziellen Dokumentation finden Sie Details zu allen in CAShapeLayer verfügbaren Eigenschaften.

Als nächstes legen Sie die folgenden Methoden in der Regenbogen-Klasse:

override func drawRect(rect: CGRect) { 
    // Add ARCs 
    self.addCirle(80, capRadius: 20, color: self.firstColor) 
    self.addCirle(150, capRadius: 20, color: self.secondColor) 
    self.addCirle(215, capRadius: 20, color: self.thirdColor) 
} 

func addCirle(arcRadius: CGFloat, capRadius: CGFloat, color: UIColor) { 
    let X = CGRectGetMidX(self.bounds) 
    let Y = CGRectGetMidY(self.bounds) 

    // Bottom Oval 
    let pathBottom = UIBezierPath(ovalInRect: CGRectMake((X - (arcRadius/2)), (Y - (arcRadius/2)), arcRadius, arcRadius)).CGPath 
    self.addOval(20.0, path: pathBottom, strokeStart: 0, strokeEnd: 0.5, strokeColor: color, fillColor: UIColor.clearColor(), shadowRadius: 0, shadowOpacity: 0, shadowOffsset: CGSizeZero) 

    // Middle Cap 
    let pathMiddle = UIBezierPath(ovalInRect: CGRectMake((X - (capRadius/2)) - (arcRadius/2), (Y - (capRadius/2)), capRadius, capRadius)).CGPath 
    self.addOval(0.0, path: pathMiddle, strokeStart: 0, strokeEnd: 1.0, strokeColor: color, fillColor: color, shadowRadius: 5.0, shadowOpacity: 0.5, shadowOffsset: CGSizeZero) 

    // Top Oval 
    let pathTop = UIBezierPath(ovalInRect: CGRectMake((X - (arcRadius/2)), (Y - (arcRadius/2)), arcRadius, arcRadius)).CGPath 
    self.addOval(20.0, path: pathTop, strokeStart: 0.5, strokeEnd: 1.0, strokeColor: color, fillColor: UIColor.clearColor(), shadowRadius: 0, shadowOpacity: 0, shadowOffsset: CGSizeZero) 

} 

Die Standardimplementierung der drawRect Methode nichts tut. Um Kreise in der Ansicht zu zeichnen, überschreiben wir die Methode, um unseren eigenen Zeichnungscode zu implementieren. Die Methode addCircle enthält drei Parameter: arcRadius, capRadius und color. Der arcRadius ist der Radius des Kreises, während der capRadius der Radius der abgerundeten Kappe ist.

Die addCircle Methode nutzt UIBezierPath die Bögen zu zeichnen und es funktioniert wie folgt:

First it draws a half circle at the bottom 
Next it draws a full small circle at the edge of the arc. 
Finally, it draws the other half of the circle 

Im drawRect Methode, rufen wir die addCircle Methode dreimal mit unterschiedlichem Radius und Farbe. Diese Abbildung zeigt, wie die Kreise gezeichnet werden: enter image description here

Tipp: Wenn Sie weitere Informationen zu UIBezierPath benötigen, können Sie sich die offizielle Dokumentation von Apple ansehen.

Mit den IBInspectable Eigenschaften, Sie sind jetzt frei, die Farbe jeden Kreises direkt im Interface Builder ohne Tauchen in den Code zu ändern:

Natürlich können Sie weitere arcRadius als IBInspectable Eigenschaft aus. Ich überlasse es als Übung für dich.

enter image description here

enter image description here

für Beispiel-Code finden Sie hier: https://github.com/appcoda/Rainbow-IBDesignable-Demo

+0

Mann, das ist absolut verrückt, der Aufwand für eine Antwort! So viel Respekt @prince. –

+12

Großartig für IBDesignable geschrieben, aber die Anforderung des Benutzers für XIB-Dateien konnte nicht beantwortet werden. – mobilemonkey

+0

@mobilemonkey vereinbart. Ich denke nicht, dass diese Antwort das Kopfgeld verdient. – Sid

4

ich das gleiche Problem hatte und ich es geschafft, es zu beheben.

Swift 3

let bundle = Bundle(for: MyView.self) 
let view = UINib(nibName: "MyView", bundle: bundle).instantiate(withOwner: self) as! MyView 

Das wichtige Bit ist das Bündel