Benutzerdefinierte UIView-Unterklasse mit XIB in Swift

8

Ich verwende Swift und Xcode 6.4 für das, was es wert ist.

Ich habe also einen View-Controller, der einige Paare von UILabels und UIImageViews enthält. Ich wollte das UILabel-UIImageView-Paar in eine benutzerdefinierte UIView einfügen, sodass ich die gleiche Struktur innerhalb des oben erwähnten View-Controllers einfach wiederverwenden konnte. (Ich bin mir bewusst, dass dies in eine UITableView übersetzt werden könnte, aber um ~ zu lernen ~ bitte ertragen Sie mit mir). Dies ist ein komplizierterer Prozess, als ich es mir vorgestellt habe. Ich habe Schwierigkeiten, den "richtigen" Weg herauszufinden, wie dies alles in IB funktioniert.

Zur Zeit habe ich mich mit einer UIView-Unterklasse und der entsprechenden XIB herumgeschlagen, indem ich init (frame :) und init (coder) überschrieben habe, die Ansicht von der Spitze geladen und sie als Unteransicht hinzugefügt habe. Das habe ich bisher im Internet gesehen / gelesen. (Das ist ungefähr so: Ссылка ).

Das hat mir das Problem verursacht, eine Endlosschleife zwischen Init (Coder) und dem Laden der Spitze aus dem Bündel zu verursachen. Seltsamerweise erwähnen keine dieser Artikel oder vorherige Antworten auf Stack Overflow dies!

Ok, also überprüfe ich init (coder) ob die Subview schon hinzugefügt wurde. Das hat das scheinbar "gelöst". Ich fing jedoch an, ein Problem mit meinen benutzerdefinierten Ansichts-Outlets zu lösen, wenn ich versuche, ihnen Werte zuzuweisen.

Ich habe ein didSet erstellt und einen Haltepunkt hinzugefügt, um einen Blick darauf zu werfen ... sie werden definitiv an einem Punkt gesetzt, aber zu dem Zeitpunkt, an dem ich versuche, die textColor eines Labels zu ändern, ist dieses Label gleich Null. Ich reiße mir hier die Haare aus.

Wiederverwendbare Komponenten scheinen wie Software-Design 101 zu sein, aber ich habe das Gefühl, dass Apple sich gegen mich verschwört. Sollte ich Container VCs hier verwenden? Sollte ich nur Ansichten verschachteln und eine dubiose Menge an Verkaufsstellen in meinem VC haben? Warum ist das so verworren? Warum funktionieren alle Beispiele nicht für mich?

Gewünschtes Ergebnis (tun Sie so, als ob das Ganze VC ist, die Boxen sind die benutzerdefinierten uiviews, die ich haben möchte):

Danke fürs Lesen.

Das ist meine benutzerdefinierte UIView-Unterklasse. In meinem Haupt-Storyboard habe ich UIViews mit der Unterklasse als Klasse.

%Vor%

BEARBEITEN: Folgendes konnte ich bisher bekommen ...

XIB:

Ergebnis:

Problem: Wenn Sie versuchen, auf Etiketten- oder Bildausgänge zuzugreifen, sind sie gleich Null. Beim Überprüfen des Haltepunkts dieses Zugriffs sind die Unteransichten label und image vorhanden, und die Ansichtshierarchie ist wie erwartet.

Ich bin damit einverstanden, das alles in Code zu machen, wenn es genau das ist, aber ich bin nicht groß darin, Autodext im Code zu machen, also würde ich lieber nicht, wenn es einen Weg gibt, es zu vermeiden!

BEARBEITEN / FRAGE UMSCHALTEN:

Ich habe herausgefunden, wie man dafür sorgen kann, dass die Steckdosen nicht mehr Null sind.

Inspiration von dieser SO-Antwort: Loaded Nib, aber die View-Outlet wurde nicht gesetzt - neu für InterfaceBuilder , außer dass ich den View-Outlet den einzelnen Komponenten-Outlets zugewiesen habe.

Nun, das war der Punkt, an dem ich nur Scheiße gegen eine Wand warf und sah, ob sie kleben blieb. Weiß jemand, warum ich das tun musste? Was für eine dunkle Magie ist das?

    
Fozzle 01.09.2015, 22:57
quelle

2 Antworten

11

Allgemeine Hinweise zur Wiederverwendung von Ansichten

Sie haben Recht, wiederverwendbare und zusammensetzbare Elemente sind Software 101. Interface Builder ist nicht sehr gut darin.

Insbesondere sind XIBs und das Storyboard ideal, um Ansichten zu definieren, indem Sie Ansichten wiederverwenden, die im Code definiert sind. Sie sind jedoch nicht sehr gut zum Definieren von Ansichten, die Sie selbst in xibs und Storyboards wiederverwenden möchten. (Es kann getan werden, aber es ist eine fortgeschrittene Übung.)

Also, hier ist eine Faustregel. Wenn Sie eine Ansicht definieren, die Sie aus Code erneut verwenden möchten, definieren Sie sie wie gewünscht. Wenn Sie jedoch eine Ansicht definieren, die möglicherweise in einem Storyboard wiederverwendet werden soll, definieren Sie diese Ansicht im Code.

Wenn Sie also in Ihrem Fall eine benutzerdefinierte Ansicht definieren möchten, die Sie in einem Storyboard wiederverwenden möchten, würde ich das im Code tun. Wenn Sie Ihre Sicht über eine Xib definieren möchten, dann würde ich eine Sicht in Code definieren, und in ihrem Initialisierer würde sie Ihre XIB-definierte Sicht initialisieren und diese als Unteransicht konfigurieren.

Hinweis in diesem Fall

Hier ist ungefähr, wie Sie Ihre Ansicht im Code definieren würden:

%Vor%

Sie können dies jetzt in Code und / oder über ein Storyboard instanziieren, obwohl Sie in Interface Builder keine Live-Vorschau erhalten.

Alternativ können Sie eine wiederverwendbare Ansicht definieren, die im Wesentlichen auf einer xib basiert, indem Sie die xib-definierte Ansicht in eine code-definierte Ansicht einbetten:

%Vor%

Jetzt können Sie die Code-definierte Ansicht von Storyboards oder Code verwenden, und es wird seine nib-definierte Unteransicht laden (und es gibt noch keine Live-Vorschau in IB).

    
algal 01.09.2015 23:15
quelle
2

Ich war in der Lage, es herumzuarbeiten, aber die Lösung ist ein bisschen knifflig. Es ist zu debattieren, wenn der Gewinn eine Anstrengung wert ist, aber hier ist, wie ich es rein in Interface Builder implementiert habe

Zuerst habe ich eine benutzerdefinierte UIView Unterklasse namens P2View

definiert %Vor%

So sieht es im Interface Builder aus

So habe ich diese benutzerdefinierte Ansicht in den Beispielansicht-Controller eingebettet, der in einem Storyboard definiert ist. Eigenschaften von P2View werden im Attribut-Inspektor festgelegt.

Es gibt 3 erwähnenswerte Punkte

Erstens:

Benutze Bundle(for: type(of: self)) beim Laden der Feder. Dies liegt daran, dass der Interface Builder die Designables in dem separaten Prozess rendert, wobei das Hauptpaket nicht mit dem Hauptpaket identisch ist.

Zweitens:

%Vor%

Wenn Sie IBInspectables mit IBOutlets kombinieren, müssen Sie daran denken, dass die Funktionen didSet vor awakeFromNib method aufgerufen werden. Aus diesem Grund werden die Steckdosen nicht initialisiert und Ihre App wird wahrscheinlich an dieser Stelle abstürzen. Leider können Sie die Funktion didSet nicht weglassen, da der Interface Builder Ihre benutzerdefinierte Ansicht nicht rendert, so dass wir diese Datei hier als schmutzig betrachten müssen.

Drittens:

%Vor%

Wir müssen unsere Kontrollen irgendwie initialisieren. Wir konnten dies nicht tun, wenn didSet function aufgerufen wurde, also müssen wir den in den IBInspectable Eigenschaften gespeicherten Wert verwenden und sie am Ende der awakeFromNib Methode initialisieren.

So können Sie eine benutzerdefinierte Ansicht auf einem Xib implementieren, sie in ein Storyboard einbetten, sie auf einem Storyboard konfigurieren, sie rendern lassen und eine App ohne Absturz verwenden. Es erfordert einen Hack, aber es ist möglich.

    
Kamil Szostakowski 27.09.2017 22:36
quelle