Ich versuche etwas Aufwändiges zu tun, aber etwas, das möglich sein sollte. Hier ist also eine Herausforderung für alle Experten da draußen (dieses Forum ist eine Menge von euch :)).
Ich erstelle eine Fragebogen- "Komponente", die ich auf eine NavigationContoller
(meine QuestionManagerViewController
) laden möchte . Die "Komponente" ist eine "leere" Komponente UIViewController
, die je nach der zu beantwortenden Frage unterschiedliche Ansichten laden kann.
Ich mache es so:
- Erstellen Sie das Question1View-Objekt als
UIView
Unterklasse und definieren Sie einigeIBOutlets
. - Erstellen Sie (mit dem Interface Builder) das
Question1View.xib
(HIER IST, WO MEIN PROBLEM MÖGLICHERWEISE IST ). Ich habe sowohl dasUIViewController
als auch dasUIView
der Klasse Question1View festgelegt. - Ich verbinde die Steckdosen mit der Ansichtskomponente (mit IB).
Ich überschreibe das
initWithNib
von mirQuestionManagerViewController
, um so auszusehen:- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { if (self = [super initWithNibName:@"Question1View" bundle:nibBundleOrNil]) { // Custom initialization } return self; }
Wenn ich den Code ausführe, wird folgende Fehlermeldung angezeigt:
2009-05-14 15: 05: 37.152 iMobiDines [17148: 20b] *** Beenden der App aufgrund einer nicht erfassten Ausnahme '
NSInternalInconsistencyException
', Grund: '-[UIViewController _loadViewFromNibNamed:bundle:]
Die Schreibfeder "Question1View" wurde geladen, aber der Ansichtsausgang wurde nicht festgelegt.'
Ich bin sicher, dass es eine Möglichkeit gibt, die Ansicht mithilfe der NIB-Datei zu laden, ohne eine viewController-Klasse erstellen zu müssen.
quelle
Danke euch allen. Ich habe einen Weg gefunden, das zu tun, was ich wollte.
UIView
mit denIBOutlet
s, die Sie brauchen.UIViewController
(keine benutzerdefinierte Unterklasse, sondern die "echte"). Die Ansicht des Dateibesitzers ist mit der Hauptansicht verbunden und ihre Klasse wird als die aus Schritt 1) deklariert.IBOutlet
s.Das
DynamicViewController
kann seine Logik ausführen, um zu entscheiden, welche Ansicht / xib geladen werden soll. Sobald es die Entscheidung getroffen hat, setzen Sie in dieloadView
Methode so etwas ein:Das ist es!
Die
loadNibNamed
Methode des Hauptpakets sorgt dafür, dass die Ansicht initialisiert und die Verbindungen erstellt werden.Jetzt kann der ViewController abhängig von den gespeicherten Daten eine oder eine andere Ansicht anzeigen, und der "übergeordnete" Bildschirm muss sich nicht mehr mit dieser Logik befassen.
quelle
Ich bin nicht sicher, worüber einige der Antworten sprechen, aber ich muss diese Antwort hier einfügen, wenn ich das nächste Mal in Google suche. Schlüsselwörter: "Laden einer UIView von einer Schreibfeder" oder "Laden einer UIView von einer NSBundle".
Hier ist der Code fast 100% direkt von der Presse Beginning iPhone 3- Buch (Seite 247, "Verwenden der neuen Tabellenansichtszelle"):
Dies setzt voraus, dass Sie eine
UIView
Unterklasse namens habenBlah
, eine Feder namens,Blah
die a enthältUIView
Klasse die ihre Klasse gesetzt istBlah
.Kategorie: NSObject + LoadFromNib
Schnelle Erweiterung
Und ein Beispiel im Gebrauch:
quelle
isKindOf
, sind Sie vor Änderungen der Bundle-Struktur geschützt.assert
wäre wahrscheinlich eine bessere Lösung. Auf diese Weise verbergen Sie nur das Problem.for
Schleife ersetzt. Es ergänzt es.Für alle, die mehr als eine Instanz der benutzerdefinierten Ansicht verwalten müssen, dh eine Outlet-Sammlung , habe ich die Antworten @Gonso, @AVeryDev und @Olie auf folgende Weise zusammengeführt und angepasst:
Erstellen Sie eine benutzerdefinierte
MyView : UIView
und legen Sie sie als " benutzerdefinierte Klasse " des StammsUIView
in der gewünschten fest XIB fest .Erstellen Sie alle Steckdosen, die Sie benötigen
MyView
(tun Sie dies jetzt, da der IB Ihnen nach Punkt 3 vorschlägt, SteckdosenUIViewController
mit der benutzerdefinierten Ansicht und nicht wie gewünscht mit der benutzerdefinierten Ansicht zu verbinden ).Legen Sie Ihre
UIViewController
als " Dateibesitzer " der benutzerdefinierten Ansicht XIB fest .In der
UIViewController
fügen Sie eine neueUIViews
für jede Instanz dieMyView
Sie wollen, und schließen Sie sie anUIViewController
eine Schaffung Outlet Kollektion : diese Ansichten als „Wrapper“ Ansichten für die benutzerdefinierte Ansicht Instanzen handeln;Zum Schluss fügen Sie in
viewDidLoad
IhremUIViewController
Feld die folgenden Zeilen hinzu:quelle
Ich würde UINib verwenden, um eine benutzerdefinierte UIView zu instanziieren, die wiederverwendet werden soll
In diesem Fall werden folgende Dateien benötigt: MyCustomView.xib , MyCustomViewClass.h und MyCustomViewClass.m Beachten Sie, dass
[UINib instantiateWithOwner]
ein Array zurückgegeben wird. Verwenden Sie daher das Element, das die UIView widerspiegelt, die Sie wiederverwenden möchten. In diesem Fall ist es das erste Element.quelle
Sie sollten die Klasse Ihres View Controllers nicht als Unterklasse
UIView
in Interface Builder festlegen. Das ist definitiv zumindest ein Teil Ihres Problems. Lassen Sie das entweder alsUIViewController
eine Unterklasse davon oder eine andere benutzerdefinierte Klasse, die Sie haben.Was das Laden nur einer Ansicht von einer xib betrifft, ging ich davon aus, dass Sie eine Art Ansichtscontroller (auch wenn dieser nicht erweitert werden muss
UIViewController
, was für Ihre Anforderungen möglicherweise zu schwer ist ) als Eigentümer der Datei in der Benutzeroberfläche festlegen müssen Builder, wenn Sie ihn zum Definieren Ihrer Schnittstelle verwenden möchten. Ich habe ein wenig recherchiert, um dies ebenfalls zu bestätigen. Dies liegt daran, dass es sonst keine Möglichkeit gibt, auf eines der Schnittstellenelemente in der zuzugreifenUIView
, und es auch keine Möglichkeit gibt, Ihre eigenen Methoden im Code durch Ereignisse auszulösen.Wenn Sie a
UIViewController
als Eigentümer Ihrer Datei für Ihre Ansichten verwenden, können Sie es einfachinitWithNibName:bundle:
laden und das View Controller-Objekt zurückerhalten.view
Stellen Sie in IB sicher, dass Sie den Ausgang auf die Ansicht mit Ihrer Schnittstelle in der xib einstellen. Wenn Sie eine andere Art von Objekt als Datei - Besitzer verwenden, müssen Sie verwendenNSBundle
‚sloadNibNamed:owner:options:
Methode , um die Spitze zu laden, eine Instanz von Datei - Besitzer auf die Methode übergeben. Alle seine Eigenschaften werden entsprechend den in IB definierten Steckdosen richtig eingestellt.quelle
Sie können auch initWithNibName von UIViewController anstelle von loadNibNamed verwenden. Es ist einfacher, finde ich.
Jetzt müssen Sie nur noch MySubView.xib und MySubView.h / m erstellen. Setzen Sie in MySubView.xib die Owner-Klasse der Datei auf UIViewController und die View-Klasse auf MySubView.
Sie können die Position und Größe
subview
der übergeordneten xib-Datei festlegen.quelle
Dies ist eine großartige Frage (+1) und die Antworten waren fast hilfreich;) Sorry Leute, aber ich hatte verdammt viel Zeit damit, obwohl sowohl Gonso als auch AVeryDev gute Hinweise gaben. Hoffentlich hilft diese Antwort anderen.
MyVC
ist der View Controller, der all dieses Zeug enthält.MySubview
ist die Ansicht, die wir von einer xib laden wollenMySubView
, die die richtige Größe und Form hat und an der gewünschten Stelle positioniert ist.In MyVC.h haben
Vergessen
@synthesize mySubView;
Sie nicht, es in MyVC.m freizugebendealloc
.UIView *view
(möglicherweise unnötig, aber für mich funktioniert). Synthetisieren und veröffentlichen Sie es in .mMySubview
und verknüpfen Sie die Ansichtseigenschaft mit Ihrer Ansicht.IBOutlet
wie gewünscht mit denZurück in MyVC.m, haben
Das Knifflige für mich war: Die Hinweise in den anderen Antworten luden meine Ansicht aus der xib, ersetzten aber NICHT die Ansicht in MyVC (duh!) - ich musste das selbst austauschen.
Um Zugriff auf
mySubview
die Methoden von zu erhalten, muss dieview
Eigenschaft in der .xib-Datei auf festgelegt werdenMySubview
. Ansonsten kommt es als schlichtes altes zurückUIView
.Wenn es eine Möglichkeit gibt,
mySubview
direkt von seinem eigenen xib zu laden , würde das rocken, aber das brachte mich dahin, wo ich sein musste.quelle
Das sollte einfacher sein. Am Ende habe ich
UIViewController
einenloadNib:inPlaceholder:
Selektor erweitert und hinzugefügt . Jetzt kann ich sagenHier ist der Code für die Kategorie (er macht die gleiche Rigamarole wie von Gonso beschrieben):
quelle
In kurzer Zeit
Eigentlich war meine Lösung für dieses Problem, die Ansicht in eine viewDidLoad in meinem CustonViewController zu laden, wo ich die Ansicht wie folgt verwenden wollte:
Laden Sie die Ansicht nicht in eine
loadView()
Methode! Die loadView-Methode dient zum Laden der Ansicht für Ihren benutzerdefinierten ViewController.quelle
Auch ich wollte etwas Ähnliches machen, das habe ich gefunden: (SDK 3.1.3)
Ich habe einen View Controller A (der selbst einem Nav-Controller gehört), der VC B per Knopfdruck lädt:
In AViewController.m
Jetzt hat VC B seine Schnittstelle von Bnib, aber wenn eine Taste gedrückt wird, möchte ich in einen 'Bearbeitungsmodus' wechseln, der eine separate Benutzeroberfläche von einer anderen Feder hat, aber ich möchte keine neue VC für den Bearbeitungsmodus. Ich möchte, dass die neue Feder meinem vorhandenen B VC zugeordnet wird.
Also, in BViewController.m (in Knopfdruckmethode)
Drücken Sie dann auf einer anderen Taste (um den Bearbeitungsmodus zu verlassen):
und ich bin zurück zu meinem ursprünglichen Bnib.
Dies funktioniert gut, aber beachten Sie, dass meine EditMode.nib nur 1 Objekt der obersten Ebene enthält, ein UIView-Objekt. Es spielt keine Rolle, ob der Eigentümer der Datei in dieser Schreibfeder als BViewController oder als Standard-NSObject festgelegt ist, ABER stellen Sie sicher, dass das View Outlet im Eigentümer der Datei NICHT auf irgendetwas festgelegt ist. Wenn dies der Fall ist, erhalte ich einen Absturz von exc_bad_access und xcode lädt 6677-Stack-Frames, die eine interne UIView-Methode zeigen, die wiederholt aufgerufen wird. Sieht also wie eine Endlosschleife aus. (Das View Outlet ist jedoch in meinem ursprünglichen Bnib eingestellt)
Hoffe das hilft.
quelle
Ich habe eine Kategorie erstellt, die mir gefällt:
UIView+NibInitializer.h
UIView+NibInitializer.m
Rufen Sie dann so an:
Verwenden Sie einen Federnamen, wenn Ihre Feder einen anderen Namen als den Namen Ihrer Klasse hat.
Um es in Ihren Unterklassen für zusätzliches Verhalten zu überschreiben, könnte es folgendermaßen aussehen:
quelle
Für Swift-Benutzer mit gestaltbarer Option:
UIView
Unterklasse und eine xib-Datei , die wir nach unserem eigenen Klassennamen benennen: in unserem Fall MemeView. Denken Sie innerhalb der Meme View-Klasse daran, sie als mit der designierbar zu definieren@IBDesignable
vor der Klassendeklaration AttributDenken Sie daran, den Eigentümer der Datei in der xib mit unserer benutzerdefinierten
UIView
Unterklasse im Indetity Inspector-Bedienfeld festzulegenIn der xib-Datei können wir jetzt unsere Schnittstelle erstellen, Einschränkungen vornehmen, Outlets, Aktionen usw. erstellen.
Wir müssen einige Methoden in unsere benutzerdefinierte Klasse implementieren, um die xib nach der Initialisierung zu öffnen
class XibbedView: UIView {
}}
In unserer benutzerdefinierten Klasse können wir auch einige überprüfbare Eigenschaften definieren, um die vollständige Kontrolle über sie vom Interface Builder aus zu haben
@IBDesignable class MemeView: XibbedView {
}}
Einige Beispiele:
Wenn wir weitere Informationen hinzufügen müssen, während die Ansicht in einem Storyboard oder einer anderen xib angezeigt wird
prepareForInterfaceBuilder()
, wird diese Methode nur beim Öffnen der Datei im Interface Builder ausgeführt. Wenn Sie alles getan haben, was ich geschrieben habe, aber nichts funktioniert, können Sie eine Sigle-Ansicht durch Hinzufügen von Haltepunkten in ihrer Implementierung debuggen. Hier ist die Ansichtshierarchie.Ich hoffe, dies hilft, ein vollständiges Beispiel kann hier heruntergeladen werden
quelle
let nib = loadNib(nibName)
Dies ist eine XibbedView-Instanz. Wenn Sie "addSubview (nib)" aufrufen, fügen Sie eine XibbedView-Instanz einer anderen XibbedView-Instanz hinzu.Ich fand diesen Blogeintrag von Aaron Hillegass (Autor, Ausbilder, Cocoa Ninja) sehr aufschlussreich. Selbst wenn Sie seinen modifizierten Ansatz zum Laden von NIB-Dateien über einen bestimmten Initialisierer nicht anwenden, werden Sie wahrscheinlich zumindest ein besseres Verständnis des laufenden Prozesses erhalten. Ich habe diese Methode in letzter Zeit mit großem Erfolg angewendet!
quelle
Die vorherige Antwort berücksichtigt keine Änderung der NIB (XIB) -Struktur, die zwischen 2.0 und 2.1 des iPhone SDK aufgetreten ist. Benutzerinhalte beginnen jetzt bei Index 0 anstelle von 1.
Sie können das 2.1-Makro verwenden, das für alle Versionen 2.1 und höher gültig ist (das sind zwei Unterstriche vor IPHONE:
Für die meisten unserer Anwendungen verwenden wir eine ähnliche Technik.
Barney
quelle
Ich hatte Grund, dasselbe zu tun (programmgesteuertes Laden einer Ansicht aus einer XIB-Datei), aber ich musste dies vollständig aus dem Kontext einer Unterklasse einer Unterklasse von a heraus tun
UIView
(dh ohne den Ansichts-Controller in irgendeiner Weise einzubeziehen). Zu diesem Zweck habe ich diese Dienstprogrammmethode erstellt:Dann rufe ich es aus der
initWithFrame
Methode meiner Unterklasse folgendermaßen auf :Gepostet für allgemeines Interesse; Wenn jemand Probleme sieht, ohne dies zu tun, lassen Sie es mich bitte wissen.
quelle
Hier ist eine Möglichkeit, dies in Swift zu tun (derzeit wird Swift 2.0 in XCode 7 Beta 5 geschrieben).
UIView
Erstellen Sie aus Ihrer Unterklasse, die Sie im Interface Builder als "Benutzerdefinierte Klasse" festgelegt haben, eine Methode wie diese (meine Unterklasse heißt RecordingFooterView):Dann können Sie es einfach so nennen:
let recordingFooterView = RecordingFooterView.loadFromNib()
quelle
Keine der Antworten erklärt, wie das eigenständige XIB erstellt wird, das die Wurzel dieser Frage ist. Es gibt kein
Xcode 4
Option zum "Erstellen einer neuen XIB-Datei".Um dies zu tun
Dies mag einfach erscheinen, erspart Ihnen jedoch einige Minuten beim Stöbern, da das Wort "XIB" nirgendwo vorkommt.
quelle
@ AVeryDev
6) So hängen Sie die geladene Ansicht an die Ansicht Ihres View Controllers an:
Vermutlich ist es notwendig, es aus der Ansicht zu entfernen, um Speicherlecks zu vermeiden.
Zur Verdeutlichung: Der View Controller verfügt über mehrere IBOutlets, von denen einige (wie üblich) mit Elementen in der ursprünglichen Nib-Datei und einige mit Elementen in der geladenen Nib verbunden sind. Beide Federn haben die gleiche Besitzerklasse. Die geladene Ansicht überlagert die ursprüngliche.
Tipp: Setzen Sie die Deckkraft der Hauptansicht in der geladenen Feder auf Null, damit die Elemente der ursprünglichen Feder nicht verdeckt werden.
quelle
Nachdem ich viele Stunden verbracht hatte, schmiedete ich folgende Lösung. Befolgen Sie diese Schritte, um benutzerdefinierte zu erstellen
UIView
.1) Erstellen Sie die von UIView geerbte Klasse myCustomView .
2) Erstellen .xib mit dem Namen myCustomView .
3) Klasse von ändern UIView in Ihrer .xib Datei, assign myCustomView Klasse gibt.
4) Erstellen Sie IBOutlets
5) Laden Sie .xib in myCustomView * customView . Verwenden Sie den folgenden Beispielcode.
quelle
Kürzeste Version:
quelle
Ich habe die Konvention, xibs mit Ansichten darin zu benennen, die mit der Ansicht identisch sind. Gleich wie bei einem View Controller. Dann muss ich keine Klassennamen in Code schreiben. Ich lade ein UIView aus einer gleichnamigen NIB-Datei.
Beispiel für eine Klasse namens MyView.
Erstellen Sie in Ihrem Code eine neue MyView wie folgt:
MyView * myView = [MyView nib_viewFromNibWithOwner: owner];
Hier ist die Kategorie dafür:
Ich würde dann Schaltflächen mit Aktionen des Controllers verbinden, den ich verwende, und Dinge auf Etiketten festlegen, indem ich die Ausgänge in meiner Unterklasse für benutzerdefinierte Ansichten verwende.
quelle
So laden Sie programmgesteuert eine Ansicht von einer Feder / XIB in Swift 4:
quelle
Am Ende habe ich UIView eine Kategorie hinzugefügt:
Erklärung hier: Viewcontroller lädt weniger Views in iOS & Mac
quelle