Ursprüngliche Lösung
- Ich habe eine XIB und eine Klasse namens SomeView erstellt (aus Bequemlichkeits- und Lesbarkeitsgründen denselben Namen verwendet). Ich habe beide auf einem UIView basiert.
- In der XIB habe ich die Klasse "File's Owner" in SomeView (im Identitätsinspektor) geändert.
- Ich habe in SomeView.swift einen UIView-Ausgang erstellt, der mit der Ansicht der obersten Ebene in der XIB-Datei verknüpft ist (der Einfachheit halber "Ansicht" genannt). Ich habe dann nach Bedarf weitere Steuerelemente zu anderen Steuerelementen in der XIB-Datei hinzugefügt.
- In SomeView.swift habe ich die XIB in den Initialisierer "init with code" geladen. Es besteht keine Notwendigkeit, "sich selbst" etwas zuzuweisen. Sobald das XIB geladen ist, sind alle Steckdosen verbunden, einschließlich der Ansicht der obersten Ebene. Das einzige, was fehlt, ist das Hinzufügen der Draufsicht zur Ansichtshierarchie:
.
class SomeView: UIView {
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
NSBundle.mainBundle().loadNibNamed("SomeView", owner: self, options: nil)
self.addSubview(self.view); // adding the top level view to the view hierarchy
}
...
}
Beachten Sie, dass ich auf diese Weise eine Klasse erhalte, die sich selbst von nib lädt. Ich könnte dann SomeView als Klasse verwenden, wenn UIView im Projekt verwendet werden könnte (im Interface Builder oder programmgesteuert).
Update - mit Swift 3-Syntax
Das Laden einer xib in der folgenden Erweiterung wird als Instanzmethode geschrieben, die dann von einem Initialisierer wie dem oben genannten verwendet werden kann:
extension UIView {
@discardableResult // 1
func fromNib<T : UIView>() -> T? { // 2
guard let contentView = Bundle(for: type(of: self)).loadNibNamed(String(describing: type(of: self)), owner: self, options: nil)?.first as? T else { // 3
// xib not loaded, or its top view is of the wrong type
return nil
}
self.addSubview(contentView) // 4
contentView.translatesAutoresizingMaskIntoConstraints = false // 5
contentView.layoutAttachAll(to: self) // 6
return contentView // 7
}
}
- Die Verwendung eines verwerfbaren Rückgabewerts, da die zurückgegebene Ansicht für den Anrufer meistens nicht von Interesse ist, wenn alle Steckdosen bereits verbunden sind.
- Dies ist eine generische Methode, die ein optionales Objekt vom Typ UIView zurückgibt. Wenn die Ansicht nicht geladen werden kann, wird null zurückgegeben.
- Versuch, eine XIB-Datei mit demselben Namen wie die aktuelle Klasseninstanz zu laden. Wenn dies fehlschlägt, wird nil zurückgegeben.
- Hinzufügen der Ansicht der obersten Ebene zur Ansichtshierarchie.
- In dieser Zeile wird davon ausgegangen, dass wir Einschränkungen verwenden, um die Ansicht zu gestalten.
- Diese Methode fügt obere, untere, führende und nachfolgende Einschränkungen hinzu - indem die Ansicht von allen Seiten an "self" angehängt wird ( Details siehe: https://stackoverflow.com/a/46279424/2274829 ).
- Rückgabe der Ansicht der obersten Ebene
Und die Aufrufermethode könnte folgendermaßen aussehen:
final class SomeView: UIView { // 1.
required init?(coder aDecoder: NSCoder) { // 2 - storyboard initializer
super.init(coder: aDecoder)
fromNib() // 5.
}
init() { // 3 - programmatic initializer
super.init(frame: CGRect.zero) // 4.
fromNib() // 6.
}
// other methods ...
}
- SomeClass ist eine UIView-Unterklasse, die ihren Inhalt aus einer SomeClass.xib-Datei lädt. Das Schlüsselwort "final" ist optional.
- Ein Initialisierer für die Verwendung der Ansicht in einem Storyboard (denken Sie daran, SomeClass als benutzerdefinierte Klasse Ihrer Storyboard-Ansicht zu verwenden).
- Ein Initialisierer für das programmgesteuerte Erstellen der Ansicht (dh: "let myView = SomeView ()").
- Verwenden eines Rahmens mit Nullen, da diese Ansicht mithilfe des automatischen Layouts erstellt wird. Beachten Sie, dass eine "init (frame: CGRect) {..}" - Methode nicht unabhängig erstellt wird, da das automatische Layout ausschließlich in unserem Projekt verwendet wird.
- & 6. Laden der xib-Datei mit der Erweiterung.
Kredit: Die Verwendung einer generischen Erweiterung in dieser Lösung wurde von Roberts Antwort unten inspiriert.
Bearbeiten
Ändern von "Ansicht" in "Inhaltsansicht", um Verwirrung zu vermeiden. Außerdem wurde der Array-Index in ".first" geändert.
File's Owner
genau richtig ist ... Danke!fromNib()
von inneninit(coder aDecoder: NSCoder)
erzeugt eine Endlosschleife, da beim Laden der Feder innerhalb derfromNib()
Methode Folgendes aufgerufen wird:init(coder aDecoder: NSCoder)
Mein Beitrag:
Dann nenne es so:
..oder auch:
quelle
Die Möglichkeit,
-> Self
schnell zurückzukehren, vereinfacht dies ein wenig. Zuletzt bestätigt auf Swift 5.Wenn Ihre
.xib
Datei und Unterklasse denselben Namen haben, können Sie Folgendes verwenden:Wenn Sie einen benutzerdefinierten Namen haben, verwenden Sie:
HINWEIS:
Wenn die Fehlermeldung "Ansicht vom Typ YourType nicht gefunden in ..." angezeigt wird, haben Sie die Klasse der Ansicht in der
.xib
Datei nicht festgelegtWählen Sie Ihre Ansicht in der
.xib
Datei aus und drücken Siecmd + opt + 4
und geben Sie in derclass
Eingabe Ihre Klasse einquelle
let myCustomView = UIView.fromNib() as? CustomView
. In diesem FallT.self
beschließt,UIView
stattCustomView
und es nicht um die Spitze zu finden. Ich bin mir nicht sicher, warum dies so ist - vielleicht der abgeleitete Typ für daslet
Mittel, als das die Funktion aufgerufen wirdUIView
?Versuchen Sie folgenden Code.
Bearbeiten:
quelle
Swift 4-Protokollerweiterungen
Annahme
Diese Implementierung setzt voraus, dass die Nib denselben Namen wie die UIView-Klasse hat. Ex. MyView.xib. Sie können dieses Verhalten ändern, indem Sie nibName () in MyView implementieren, um einen anderen Namen als die Standardimplementierungserweiterung zurückzugeben.
In der xib ist der Dateieigentümer MyView und die Stammansichtsklasse MyView.
Verwendung
quelle
Ich habe dies mit Swift durch den folgenden Code erreicht:
Vergessen Sie nicht , Ihre XIB zu verbinden Ansicht Steckdose Ansicht Steckdose in schnellen definiert. Sie können First Responder auch auf Ihren benutzerdefinierten Klassennamen einstellen, um zusätzliche Steckdosen anzuschließen.
Hoffe das hilft!
quelle
Getestet in Xcode 7 Beta 4, Swift 2.0 und iOS9 SDK. Der folgende Code weist der uiview xib zu. Sie können diese benutzerdefinierte xib-Ansicht im Storyboard verwenden und auch auf das IBOutlet-Objekt zugreifen.
Greifen Sie programmgesteuert auf die benutzerdefinierte Ansicht zu
Quellcode - https://github.com/karthikprabhuA/CustomXIBSwift
quelle
Wenn Sie viele benutzerdefinierte Ansichten in Ihrem Projekt haben, können Sie Klassen wie erstellen
UIViewFromNib
Swift 2.3
Swift 3
Und in jeder Klasse, von der nur geerbt wird
UIViewFromNib
, können Sie auch dienibName
Eigenschaft überschreiben, wenn die.xib
Datei einen anderen Namen hat:quelle
Aufbauend auf den oben genannten Lösungen.
Dies funktioniert in allen Projektpaketen und erfordert keine Generika, wenn fromNib () aufgerufen wird.
Swift 2
Swift 3
Kann so verwendet werden:
Oder so:
quelle
Swift 4
Vergessen Sie nicht, ".first as? CustomView" zu schreiben.
Wenn Sie überall verwenden möchten
Die beste Lösung ist die Antwort von Robert Gummesson .
Dann nenne es so:
quelle
quelle
self
wird implizit von alleninit
Methoden zurückgegeben ...Eine gute Möglichkeit, dies mit Swift zu tun, ist die Verwendung einer Aufzählung.
Dann können Sie in Ihrem Code einfach Folgendes verwenden:
quelle
Ich bevorzuge diese Lösung (basierend auf der Antwort wenn @ GK100):
In SomeView.swift habe ich die XIB in den Initialisierer
init
oder geladeninit:frame: CGRect
. Es besteht keine Notwendigkeit, "sich selbst" etwas zuzuweisen. Sobald das XIB geladen ist, sind alle Steckdosen verbunden, einschließlich der Ansicht der obersten Ebene. Das einzige, was fehlt, ist das Hinzufügen der Draufsicht zur Ansichtshierarchie:quelle
Swift 3- Version von Logans Antwort
quelle
Hier ist eine saubere und deklarative Methode zum programmgesteuerten Laden einer Ansicht mithilfe eines Protokolls und einer Protokollerweiterung (Swift 4.2):
Und Sie können dies so verwenden:
Einige zusätzliche Überlegungen :
Custom Class
festgelegt ist (und die von dort festgelegten Ausgänge / Aktionen) und nicht die des Dateibesitzers .quelle
Ich mache einfach so:
In diesem Beispiel wird die erste Ansicht in der Schreibfeder "MyView.xib" im Hauptpaket verwendet. Sie können jedoch entweder den Index, den Nib-Namen oder das Bundle variieren (standardmäßig main).
Früher habe ich Ansichten in die View-Init-Methode geweckt oder generische Methoden wie in den obigen Lösungen erstellt (die übrigens intelligent sind), aber ich mache das nicht mehr.
Auf diese Weise kann ich verschiedene Layouts oder Merkmale verwenden und dabei die gleiche Ansichtslogik und den gleichen Code beibehalten.
Ich finde es einfacher, ein Factory-Objekt (normalerweise den viewController, der die Ansicht verwendet) so zu erstellen, wie es benötigt wird. Manchmal benötigen Sie einen Eigentümer (normalerweise, wenn die erstellte Ansicht eine mit dem Ersteller verbundene Steckdose hat), manchmal nicht.
Das ist wahrscheinlich der Grund, warum Apple keine
initFromNib
Methode in seine UIView-Klasse aufgenommen hat ...Um ein Beispiel vom Boden zu nehmen, Sie wissen nicht, wie Sie geboren werden. Du bist gerade geboren. So sind die Ansichten;)
quelle
Sie müssen lediglich die init-Methode in Ihrer
UIView
Klasse aufrufen .Mach es so:
Wenn Sie diese Ansicht nun als Unteransicht in View Controller hinzufügen möchten, gehen Sie folgendermaßen in der Datei view controller.swift vor:
quelle
Ähnlich wie einige der obigen Antworten, jedoch eine konsistentere Swift3 UIView-Erweiterung:
Dies bietet den Komfort, die Klasse von einer selbst benannten Feder, aber auch von anderen Federn / Bundles laden zu können.
quelle
Sie können dies über das Storyboard tun. Fügen Sie einfach die entsprechenden Einschränkungen für die Ansicht hinzu. Sie können dies einfach tun, indem Sie eine beliebige Ansicht aus Ihrer eigenen Unterklasse unterteilen. Sagen wir
BaseView
:Ziel c
Swift 4
Ich biete 2 Varianten an, wie man Einschränkungen hinzufügt - allgemeine und innerhalb der Sprache des visuellen Formats - wählen Sie eine beliebige aus :)
Außerdem wird standardmäßig davon ausgegangen, dass der
xib
Name denselben Namen wie der Name der Implementierungsklasse hat. Wenn nein - einfach ändernxibName
Parameter .Wenn Sie Ihre Ansicht von unterklassifizieren, können
BaseView
Sie problemlos eine beliebige Ansicht einfügen und eine Klasse in IB angeben.quelle
quelle
Leistungsstärkere Version basierend auf Logans Antwort
Und Sie können wie verwenden
quelle
Die bequemste Implementierung. Hier benötigen Sie zwei Methoden, um direkt zum Objekt Ihrer Klasse zurückzukehren, nicht zu UIView.
Beispiel:
quelle
Wenn Sie möchten, dass die Swift UIView-Unterklasse vollständig in sich geschlossen ist und mit init oder init (frame :) instanziiert werden kann, ohne die Implementierungsdetails der Verwendung einer Nib offenzulegen, können Sie eine Protokollerweiterung verwenden, um dies zu erreichen. Diese Lösung vermeidet die verschachtelte UIView-Hierarchie, wie sie von vielen anderen Lösungen vorgeschlagen wird.
quelle
quelle
Ich bevorzuge die folgende Erweiterung
Der Unterschied zwischen dieser und der am häufigsten beantworteten Erweiterung besteht darin, dass Sie keine Konstante oder Variable speichern müssen.
quelle
quelle