Ich denke, es ist ein ziemlich verbreitetes Paradigma , das je nach Geschäftslogik UIViews
meistens ein- UILabels
und ausgeblendet wird. Meine Frage ist, wie AutoLayout am besten verwendet wird, um auf ausgeblendete Ansichten zu reagieren, als ob ihr Frame 0x0 wäre. Hier ist ein Beispiel für eine dynamische Liste von 1-3 Funktionen.
Im Moment habe ich einen oberen Bereich von 10 Pixel von der Schaltfläche bis zum letzten Etikett, der offensichtlich nicht nach oben rutscht, wenn das Etikett ausgeblendet ist. Ab sofort habe ich einen Ausgang für diese Einschränkung erstellt und die Konstante abhängig von der Anzahl der angezeigten Beschriftungen geändert. Dies ist offensichtlich etwas hackig, da ich negative konstante Werte verwende, um den Knopf über den versteckten Frames nach oben zu drücken. Es ist auch schlecht, weil es nicht auf tatsächliche Layoutelemente beschränkt ist, sondern nur hinterhältige statische Berechnungen, die auf bekannten Höhen / Auffüllungen anderer Elemente basieren und offensichtlich gegen das kämpfen, wofür AutoLayout entwickelt wurde.
Ich könnte natürlich nur neue Einschränkungen in Abhängigkeit von meinen dynamischen Beschriftungen erstellen, aber das ist viel Mikromanagement und viel Ausführlichkeit für den Versuch, nur ein Leerzeichen zu reduzieren. Gibt es bessere Ansätze? Ändern Sie die Frame-Größe 0,0 und lassen Sie AutoLayout ohne Manipulation von Einschränkungen arbeiten? Ansichten komplett entfernen?
Um ehrlich zu sein, erfordert das Ändern der Konstante aus dem Kontext der verborgenen Ansicht eine einzige Codezeile mit einfacher Berechnung. Das Wiederherstellen neuer Einschränkungen mit constraintWithItem:attribute:relatedBy:toItem:attribute:multiplier:constant:
scheint so schwer zu sein.
Edit Feb 2018 : Siehe Bens Antwort mit UIStackView
s
quelle
Antworten:
UIStackView
ist wahrscheinlich der richtige Weg für iOS 9+. Es verarbeitet nicht nur die ausgeblendete Ansicht, sondern entfernt bei korrekter Einrichtung auch zusätzliche Abstände und Ränder.quelle
Meine persönliche Präferenz für das Ein- und Ausblenden von Ansichten besteht darin, ein IBOutlet mit der entsprechenden Einschränkung für Breite oder Höhe zu erstellen.
Ich aktualisiere dann den
constant
Wert,0
um ihn auszublenden, oder was auch immer der Wert sein soll, um ihn anzuzeigen.Der große Vorteil dieser Technik besteht darin, dass relative Einschränkungen beibehalten werden. Angenommen, Sie haben Ansicht A und Ansicht B mit einer horizontalen Lücke von x . Wenn die Breite von Ansicht A festgelegt
constant
ist,0.f
wird Ansicht B nach links verschoben, um diesen Bereich zu füllen.Es ist nicht erforderlich, Einschränkungen hinzuzufügen oder zu entfernen, was eine schwere Operation ist. Das einfache Aktualisieren der Einschränkungen reicht aus
constant
.quelle
Die Lösung, eine Konstante zu verwenden,
0
wenn sie ausgeblendet ist, und eine andere Konstante, wenn Sie sie erneut anzeigen, ist funktional, aber unbefriedigend, wenn Ihr Inhalt eine flexible Größe hat. Sie müssten Ihren flexiblen Inhalt messen und eine Konstante zurücksetzen. Dies fühlt sich falsch an und hat Probleme, wenn sich die Größe des Inhalts aufgrund von Server- oder UI-Ereignissen ändert.Ich habe eine bessere Lösung.
Die Idee ist, die Höhenregel 0 so festzulegen, dass sie eine hohe Priorität hat, wenn wir das Element ausblenden, damit es keinen Platz für die automatische Auslagerung beansprucht.
So machen Sie das:
1. Richten Sie im Interface Builder eine Breite (oder Höhe) von 0 mit niedriger Priorität ein.
Interface Builder schreit nicht über Konflikte, weil die Priorität niedrig ist. Testen Sie das Höhenverhalten, indem Sie die Priorität vorübergehend auf 999 setzen (1000 darf nicht programmgesteuert mutieren, daher wird es nicht verwendet). Der Interface Builder wird jetzt wahrscheinlich über widersprüchliche Einschränkungen schreien. Sie können diese Probleme beheben, indem Sie Prioritäten für verwandte Objekte auf etwa 900 festlegen.
2. Fügen Sie eine Steckdose hinzu, damit Sie die Priorität der Breitenbeschränkung im Code ändern können:
3. Passen Sie die Priorität an, wenn Sie Ihr Element ausblenden:
quelle
In diesem Fall ordne ich die Höhe des Autorenetiketts einem geeigneten IBOutlet zu:
und wenn ich die Höhe der Einschränkung auf 0.0f setze, behalten wir das "Auffüllen" bei, da die Höhe der Wiedergabetaste dies zulässt.
quelle
Hier gibt es viele Lösungen, aber mein üblicher Ansatz ist wieder anders :)
Richten Sie zwei Arten von Einschränkungen ein, die der Antwort von Jorge Arimany und TMin ähneln:
Alle drei markierten Einschränkungen haben den gleichen Wert für die Konstante. Für die mit A1 und A2 gekennzeichneten Einschränkungen ist die Priorität auf 500 festgelegt, während für die mit B gekennzeichnete Einschränkung die Priorität auf 250 (oder
UILayoutProperty.defaultLow
im Code) festgelegt ist.Verbinden Sie die Einschränkung B mit einem IBOutlet. Wenn Sie das Element ausblenden, müssen Sie nur die Einschränkungspriorität auf hoch (750) setzen:
constraintB.priority = .defaultHigh
Wenn das Element jedoch sichtbar ist, setzen Sie die Priorität wieder auf niedrig (250):
constraintB.priority = .defaultLow
Der (zugegebenermaßen geringfügige) Vorteil dieses Ansatzes gegenüber dem bloßen Ändern
isActive
für Einschränkung B besteht darin, dass Sie immer noch eine funktionierende Einschränkung haben, wenn das vorübergehende Element auf andere Weise aus der Ansicht entfernt wird.quelle
Unterklassifizieren Sie die Ansicht und überschreiben Sie sie
func intrinsicContentSize() -> CGSize
. Kehren Sie einfach zurück,CGSizeZero
wenn die Ansicht ausgeblendet ist.quelle
invalidateIntrinsicContentSize
. Sie können dies in einem überschriebenen tunsetHidden
.Ich habe gerade herausgefunden, dass man ein UILabel ausblenden und seinen Text auf eine leere Zeichenfolge setzen muss, damit es keinen Speicherplatz beansprucht. (iOS 9)
Das Wissen um diese Tatsache / diesen Fehler könnte einigen Leuten helfen, ihre Layouts zu vereinfachen, möglicherweise sogar das der ursprünglichen Frage, also dachte ich mir, ich würde es posten.
quelle
Ich bin überrascht, dass es
UIKit
für dieses gewünschte Verhalten keinen eleganteren Ansatz gibt . Es scheint eine sehr häufige Sache zu sein, dies tun zu wollen.Da das Verbinden von Einschränkungen mit
IBOutlets
und das Setzen ihrer Konstanten auf0
Glück (undNSLayoutConstraint
Warnungen verursachte, wenn Ihre Ansicht Unteransichten hatte), habe ich beschlossen, eine Erweiterung zu erstellen, die einen einfachen, zustandsbehafteten Ansatz zum Ausblenden /UIView
Anzeigen von Einschränkungen mit automatischem Layout bietetEs verbirgt lediglich die Ansicht und beseitigt äußere Einschränkungen. Wenn Sie die Ansicht erneut anzeigen, werden die Einschränkungen wieder hinzugefügt. Die einzige Einschränkung besteht darin, dass Sie flexible Failover-Einschränkungen für die umgebenden Ansichten festlegen müssen.
Bearbeiten Diese Antwort richtet sich an iOS 8.4 und niedriger. Verwenden Sie in iOS 9 einfach den
UIStackView
Ansatz.quelle
Die beste Vorgehensweise ist, wenn alles die richtigen Layouteinschränkungen aufweist, eine Höhe oder eine Einschränkung hinzuzufügen, je nachdem, wie die umgebenden Ansichten verschoben werden sollen, und die Einschränkung mit einer
IBOutlet
Eigenschaft zu verbinden.Stellen Sie sicher, dass Ihre Eigenschaften sind
strong
Im Code müssen Sie nur die Konstante auf 0 setzen und aktivieren , um den Inhalt auszublenden oder zu deaktivieren , um den Inhalt anzuzeigen. Dies ist besser, als den konstanten Wert zu verfälschen und ihn zu speichern und wiederherzustellen. Vergessen Sie nicht, danach anzurufen
layoutIfNeeded
.Wenn der auszublendende Inhalt gruppiert ist, empfiehlt es sich, alle Inhalte in eine Ansicht einzufügen und die Einschränkungen zu dieser Ansicht hinzuzufügen
Sobald Sie Ihr Setup haben, können Sie es in IntefaceBuilder testen, indem Sie Ihre Einschränkung auf 0 und dann auf den ursprünglichen Wert zurücksetzen. Vergessen Sie nicht, die Prioritäten anderer Einschränkungen zu überprüfen, damit im versteckten Zustand überhaupt keine Konflikte auftreten. Sie können es auch testen, indem Sie es auf 0 setzen und die Priorität auf 0 setzen. Sie sollten jedoch nicht vergessen, die höchste Priorität wieder herzustellen.
quelle
Ich erstelle eine Kategorie, um Einschränkungen einfach zu aktualisieren:
Antwort hier: Autolayout ausblenden UIView: So erhalten Sie vorhandene NSLayoutConstraint, um diese zu aktualisieren
quelle
Meine bevorzugte Methode ist der von Jorge Arimany vorgeschlagenen sehr ähnlich.
Ich ziehe es vor, mehrere Einschränkungen zu erstellen. Erstellen Sie zunächst Ihre Einschränkungen, wenn das zweite Etikett sichtbar ist. Erstellen Sie eine Steckdose für die Einschränkung zwischen der Schaltfläche und dem zweiten Etikett (wenn Sie objc verwenden, stellen Sie sicher, dass es stark ist). Diese Einschränkung bestimmt die Höhe zwischen der Schaltfläche und der zweiten Beschriftung, wenn sie sichtbar ist.
Erstellen Sie dann eine weitere Einschränkung, die die Höhe zwischen der Schaltfläche und der oberen Beschriftung angibt, wenn die zweite Schaltfläche ausgeblendet ist. Erstellen Sie einen Ausgang für die zweite Einschränkung und stellen Sie sicher, dass dieser Ausgang einen starken Zeiger hat. Deaktivieren Sie dann das
installed
Kontrollkästchen im Interface Builder und stellen Sie sicher, dass die Priorität der ersten Einschränkung niedriger als diese Priorität der zweiten Einschränkung ist.Wenn Sie die zweite Beschriftung ausblenden, schalten Sie die
.isActive
Eigenschaft dieser Einschränkungen um und rufen Sie aufsetNeedsDisplay()
Und das war's, keine magischen Zahlen, keine Mathematik. Wenn Sie mehrere Einschränkungen zum Ein- und Ausschalten haben, können Sie sogar Outlet-Sammlungen verwenden, um sie nach Bundesstaaten zu organisieren. (AKA behält alle versteckten Einschränkungen in einer OutletCollection und die nicht versteckten in einer anderen bei und iteriert einfach über jede Sammlung, um ihren .isActive-Status umzuschalten.)
Ich weiß, dass Ryan Romanchuk sagte, er wolle nicht mehrere Einschränkungen verwenden, aber ich denke, dies ist kein Mikromanagement und es ist einfacher, Ansichten und Einschränkungen programmgesteuert dynamisch zu erstellen (was er meiner Meinung nach vermeiden wollte, wenn ich es tun würde lese die Frage richtig).
Ich habe ein einfaches Beispiel erstellt, ich hoffe es ist nützlich ...
quelle
Ich werde auch meine Lösung anbieten, um Abwechslung zu bieten.) Ich finde es einfach lächerlich, eine Steckdose für die Breite / Höhe jedes Artikels plus für den Abstand zu erstellen, und sprengt den Code, die möglichen Fehler und die Anzahl der Komplikationen.
Meine Methode entfernt alle Ansichten (in meinem Fall UIImageView-Instanzen), wählt aus, welche wieder hinzugefügt werden müssen, und fügt in einer Schleife jede wieder hinzu und erstellt neue Einschränkungen. Es ist eigentlich ganz einfach, bitte folgen Sie durch. Hier ist mein schneller und schmutziger Code, um es zu tun:
Ich bekomme ein sauberes, konsistentes Layout und Abstand. Mein Code verwendet Masonry. Ich empfehle es dringend: https://github.com/SnapKit/Masonry
quelle
Probieren Sie BoxView aus , es macht das dynamische Layout übersichtlich und lesbar.
In Ihrem Fall ist es:
quelle