Gewusst wie: Self-Sizing Custom-View von XIB mit StackView-Ansicht in iOs

8

Ich habe vor kurzem angefangen, wieder in die Entwicklung von SWIFT / iOS einzutauchen und bin jetzt auf der Suche nach einem benutzerdefinierten UIControl. Für Layout und Flexibilität wird diese benutzerdefinierte Ansicht mit einem StackView erstellt.

Was ich erreichen möchte ...

... ist im Grunde genommen die gleiche Funktionalität mit dem StackView, das ich normalerweise habe, wenn ich es direkt in das Storyboard ziehe - wo es die Größe ändert, um kein Problem zu verursachen. Dies ist im Wesentlichen das selbe wie Self-Sizing Tabellenansicht Zellen.

Schaufenster

Ich kann mein CustomView auf ein einfaches Beispiel reduzieren: Es ist ein StackView mit drei Labels, Alignment auf Center , Distribution Equal Centering . Das StackView wird an die linken, rechten und oberen Layouthilfslinien angehängt (oder an nachfolgende, führende und obere). Dies kann ich leicht mit einem CustomView, geladen von XIB übersetzen in ein CustomView mit den gleichen Parametern neu erstellen - ich habe beide als Screenshot beigefügt.

Screenshot von Simple StackView

Screenshot von CustomView

Laden Sie die XIB-Datei und richten Sie sie ein.

%Vor%

Was Sie hier sehen können, ist, dass ich einfach die XIB-Datei lade, Layout-Subviews überschreibe, um den Frame an die tatsächliche Ansicht anzupassen, und das ist es.

Fragen

Meine Fragen beziehen sich also darauf, wie das normalerweise angegangen wird. Die Labels in meinem StackView haben eine intrinsische Inhaltsgröße, d. H. Normalerweise passt sich das StackView einfach an die Höhe der Labels an, ohne sich zu beschweren - wenn Sie es im Storyboard entwerfen. Wenn Sie jedoch alles in ein XIB setzen und das Layout so lassen, wie es ist, wird sich das IB über eine unbekannte Höhe beschweren, wenn die Ansicht wie im Screenshot dreifach fixiert ist (oben, vorne, hinten).

Ich habe den Auto-Layout Guide gelesen und die WWDC-Videos "Mysteries of AutoLayout" angeschaut, aber das Thema ist für mich immer noch neu und ich glaube nicht, dass ich den richtigen Ansatz gefunden habe. Also hier brauche ich Hilfe

(1) Sollte ich Constraints setzen und translatesAutoresizingMaskIntoConstraints deaktivieren?

Was ich zuerst machen könnte und sollte, ist translatesAutoresizingMaskIntoConstraints false so einzustellen, dass ich keine automatisch generierten Constraints bekomme und meine eigenen Constraints definiere. Also könnte ich loadNib folgendermaßen ändern:

%Vor%

Grundsätzlich habe ich die Ansicht so gestreckt, dass sie auf die volle Breite meiner UIView im Storyboard passt, und sie oben und unten bis oben und unten im StackView beschränkt.

Ich hatte jede Menge Probleme damit, dass XCode 8 auf mich stürzte, wenn ich diesen benutze, also bin ich mir nicht sicher, was ich davon halten soll.

(2) Oder sollte ich intrinsicContentSize ? überschreiben?

Ich könnte auch einfach intrinsicContentSize überschreiben, indem ich die Höhe aller meiner arrangedSubviews überprüfe und die höchste Höhe nehme, setze meine Ansichtshöhe darauf:

%Vor%

Während dies mir sicherlich mehr Flexibilität gibt, müsste ich auch die intrinsische Inhaltsgröße ungültig machen, den dynamischen Typ und viele andere Dinge überprüfen, die ich lieber vermeiden würde.

(3) Laden wir die XIB sogar auf "vorgeschlagene" Weise?

Oder gibt es einen besseren Weg, z.B. mit UINib.instantiate ? Ich konnte wirklich keine Best-Practice-Methode dafür finden.

(4) Warum muss ich das überhaupt machen?

Wirklich, warum? Ich habe den StackView nur in eine CustomView verschoben. Warum stoppt das StackView jetzt selbst, warum muss ich die oberen und unteren Beschränkungen einstellen?

Was bisher am meisten geholfen hat, ist das Schlüsselwort in Ссылка :

  

"Im Allgemeinen wird das automatische Layout von oben nach unten ausgeführt   Wörter, wird zuerst ein Layout für die Elternansicht und dann ein Kind ausgeführt   Ansichtslayouts werden ausgeführt. "

.. aber ich bin mir da nicht so sicher.

(5) Und warum muss ich die Einschränkungen im Code hinzufügen?

Angenommen, ich deaktiviere translatesAutoresizingMaskIntoConstraints , dann kann ich keine Einschränkungen wie für Tabellenansichtszellen in IB festlegen? Es wird immer in etwas wie label.top = top übersetzt und somit wird das Label gestreckt, anstatt dass das StackView die Größe / Höhe erbt. Außerdem kann ich das StackView nicht wirklich an seine Containeransicht im IB für die XIB-Datei anheften.

Hoffe jemand kann mir da draußen helfen. Prost!

    
martin 13.12.2016, 17:09
quelle

2 Antworten

1

Hier sind einige Antworten auf Ihre Fragen, allerdings in anderer Reihenfolge:

  

(5) Und warum muss ich die Einschränkungen im Code hinzufügen?

     

Wenn ich translateAutoresizingMaskIntoConstraints deaktiviere, dann I   kann keine Einschränkungen wie für Tabellenansichtszellen in IB festgelegt werden? Es wird immer   übersetzt in etwas wie label.top = top und damit das Label   gestreckt werden anstelle des StackView, der die Größe / Höhe erbt. Ebenfalls   Ich kann das StackView nicht wirklich an seine Containeransicht in der IB für   die XIB-Datei.

Sie müssen die Einschränkungen in Code hinzufügen, in diesem Beispiel, weil Sie eine beliebige Ansicht von einer Spitze laden und sie dann zu einem Ihrer codierten CustomView hinzufügen. Die Ansicht in der Schreibfeder hat keine vorhergehende Kenntnis davon, in welchen Kontext oder welche Hierarchie sie eingefügt wird, so dass es nicht möglich ist, im Voraus definiert zu werden, wie man sich auf eine unbekannte zukünftige Superansicht beschränkt. Im Fall von StackView auf dem Storyboard oder innerhalb einer Prototypzelle ist dieser Kontext ebenso bekannt wie seine übergeordnete Ansicht.

Eine nette Alternative, die Sie für diesen Fall in Betracht ziehen können, wenn Sie Constraints nicht manuell schreiben wollen, besteht darin, Ihre CustomView-Unterklasse UIStackView anstelle von UIView zu erstellen. Da UIStackView automatisch geeignete Einschränkungen generiert, sparen Sie die manuelle Codierung. Siehe nächste Antwort für einen Beispielcode.

  

(3) Laden ich sogar die XIB auf die "vorgeschlagene" Weise?

     

Oder gibt es einen besseren Weg, z.B. mit UINib.instantiate? Ich [...] wirklich   Ich konnte keinen Best-Practice-Weg finden.

Ich bin mir nicht bewusst, dass eine "normale" oder "richtige" Methode zum Laden einer Feder in eine benutzerdefinierte Ansicht verwendet wird. Ich habe eine Vielzahl von Ansätzen gesehen, die alle funktionieren. Ich werde jedoch feststellen, dass Sie in Ihrem Beispielcode mehr Arbeit leisten als benötigt. Hier ist ein minimaler Weg, das gleiche Ergebnis zu erreichen, aber auch eine UIStackView-Unterklasse anstelle einer UIView-Unterklasse zu verwenden (wie oben erwähnt):

%Vor%

Beachten Sie, dass CustomView jetzt eine Unterklasse von UIStackView ist und die für alle Subviews erforderlichen Einschränkungen automatisch erstellt. In diesem Fall, weil distribution und alignment beide auf .fill gesetzt sind, werden die Kanten der Unteransicht wie gewünscht an die eigenen Kanten gebunden.

  

(4) Warum muss ich das überhaupt machen?

     

Wirklich, warum? Ich habe den StackView nur in eine CustomView verschoben. Warum also?   der StackView hört jetzt auf sich selbst anzupassen, warum muss ich das Top setzen   und untere Einschränkungen?

Eigentlich ist das Schlüsselproblem hier die Eigenschaft alignment Ihres StackView von .center . Das heißt, dass die Beschriftungen in StackView vertikal zentriert sind, aber sie werden nicht an den Anfang oder das Ende des StackViews gebunden . Es ist vergleichbar mit dem Hinzufügen einer centerY-Einschränkung zu einer Unteransicht in einer Ansicht. Sie können die äußere Ansicht auf eine beliebige Höhe einstellen, und die Unteransicht wird zentriert, aber nicht die obere und untere Ansicht der äußeren Ansicht "herausgedrückt", da die zentralen Beschränkungen nur die Mittelpunkte und nicht die oberen und unteren Kanten einschränken.

In Ihrer Storyboard-Version von StackView ist die Ansichtshierarchie oberhalb von StackView bekannt, und es gibt auch Optionen zum automatischen Erstellen von Einschränkungen durch das Ändern der Größe von Masken. Wie auch immer, die endgültige StackView-Höhe ist UIKit bekannt, und die Labels werden vertikal in dieser Höhe zentriert, aber werden sie nicht wirklich beeinflussen. Sie müssen entweder die Ausrichtung Ihres StackView als .fill festlegen oder zusätzliche Beschränkungen von den Ober- und Unterseiten der Labels zum oberen und unteren Ende des StackView hinzufügen, damit das automatische Layout bestimmen kann, wie groß das StackView sein sollte sei.

  

(2) Oder sollte ich intrinsicContentSize überschreiben?

Dies würde nicht viel helfen, da die eigentliche Inhaltsgröße selbst die Kanten einer übergeordneten Ansicht nicht herausschiebt, es sei denn, die Kanten der Unteransicht sind auch auf die Kanten der übergeordneten Ansicht beschränkt. In jedem Fall erhalten Sie in diesem Fall automatisch das korrekte Verhalten des Inhaltsverhaltens, das Sie wirklich benötigen, solange Sie das oben erwähnte Problem .center alignment angehen.

  

(1) Sollte ich Constraints setzen und translatedAutoresizingMaskIntoConstraints deaktivieren?

Dies wäre normalerweise ein gültiger Ansatz. Wenn Sie UIStackView wie oben beschrieben ableiten, müssen Sie das auch nicht tun.

Zusammenfassend

Wenn Sie:

  1. Erstellen Sie Ihre CustomView als Unterklasse von UIStackView wie im obigen Beispielcode

  2. Erstellen Sie eine Ansicht in Ihrem Storyboard, die auf Ihre benutzerdefinierte Klasse CustomView festgelegt wurde. Wenn Sie möchten, dass CustomView die Größe selbst korrekt einstellt, müssen Sie Einschränkungen angeben und keine automatisch generierten Einschränkungen aus der Größenänderungsmaske verwenden.

  3. Ändere das StackView in der Schreibweise so, dass entweder alignment auf .fill gesetzt wird oder zusätzliche Abhängigkeiten zwischen dem oberen und unteren Rand von mindestens einem der Labels (höchstwahrscheinlich das große mittlere) und Oben und unten in der Stapelansicht

Dann sollte das automatische Layout korrekt funktionieren und Ihre benutzerdefinierte Ansicht mit dem StackView sollte wie erwartet aussehen.

    
Daniel Hall 27.12.2017, 20:56
quelle
1

Ihre Option 1 funktionierte für mich, nachdem einige andere nicht.

    
Michael 11.04.2017 20:32
quelle