wake-up-neo.com

Größe einer Containeransicht mit einem Controller mit dynamischer Größe in einer Bildlaufansicht

Ich versuche, eine Containeransicht mit einem Controller, der eine dynamische Höhe hat, in einer UIScrollView zu erstellen und diese automatisch mithilfe des automatischen Layouts zu skalieren.

Storyboard illustrating the setup

View Controller A ist die Bildlaufansicht, in der die Containeransicht enthalten ist. Weitere Inhalte finden Sie weiter unten.

View Controller B ist der View Controller, für den ich eine dynamische Größe haben möchte und der gesamte Inhalt in voller Höhe in der Bildlaufansicht von View Controller A angezeigt werden soll.

Ich habe Probleme mit der dynamischen Größe von B, um die Größe der Containeransicht in A automatisch festzulegen. Wenn ich jedoch eine Höhenbeschränkung für die Containeransicht in A einstelle, gilt Folgendes: Container View in A to for example 250

Es wäre die erwartete Ausgabe, wenn View Controller B auch eine Höhe von 250 haben würde. Es funktioniert auch gut für die Höhe 1000, so dass meines Erachtens alle Einschränkungen für das automatische Layout richtig eingestellt sind. Da die Höhe eigentlich dynamisch sein sollte, möchte ich leider keine Höheneinschränkung festlegen. 

Ich bin mir nicht sicher, ob es Einstellungen für den View Controller B gibt. Ich kann festlegen, dass die Größe automatisch entsprechend dem Inhalt aktualisiert wird, oder ob andere Tricks fehlen, die ich vermisst habe. Jede Hilfe wäre sehr dankbar!

Gibt es eine Möglichkeit, die Containeransicht in A entsprechend der Größe von View Controller B zu skalieren, ohne eine Höhenbeschränkung festzulegen?

Ja, da ist es. Ich habe dieses Verhalten in einem meiner eigenen Projekte erreicht.

Alles, was Sie tun müssen, ist, dem System mitzuteilen, dass es keine Einschränkungen hinzufügen sollte, die den festen Frame-Satz für Ihre Root-Ansicht im Interface Builder nachahmen. Der beste Ort dafür ist in Ihrem Container-Ansichts-Controller, wenn Ihr Einbettungssegment ausgelöst wird:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    // You might want to check if this is your embed segue here
    // in case there are other segues triggered from this view controller. 
    segue.destinationViewController.view.translatesAutoresizingMaskIntoConstraints = NO;
}

Wichtig:

Sie müssen sicherstellen, dass die Ansicht, die Sie in den Container laden, von oben nach unten eingeschränkt ist, und Sie müssen die Priorität einer der vertikalen Einschränkungen auf einen Wert unter 1000 setzen. (Es empfiehlt sich, immer die untere Einschränkung zu verwenden dazu.) Dies ist notwendig, da sich Interface Builder sonst aus gutem Grund beschwert: 

Zur Entwurfszeit hat Ihre Stammansicht eine feste Größe (Höhe). Wenn nun alle Ihre Unteransichten eine feste Höhe haben und mit festen Einschränkungen verbunden sind, die alle die gleiche Priorität haben, ist es unmöglich, alle diese Anforderungen zu erfüllen, es sei denn, die Höhe Ihrer festen Stammansicht entspricht zufällig genau der Gesamthöhe Ihrer Unteransichten und den vertikalen Beschränkungen. Wenn Sie die Priorität einer der Einschränkungen auf 999 herabsetzen, erkennt Interface Builder, welche Einschränkung zu brechen ist. Zur Laufzeit jedoch - wenn die translatesAutoresizingMaskIntoConstraints -Eigenschaft wie oben angegeben festgelegt ist - gibt es für Ihre Root-Ansicht keinen festen Rahmen mehr, und das System verwendet stattdessen Ihre 999-Prioritätsbedingung.

 Interface Builder Screenshot

80
Mischa

Aus der Antwort von @Mischa konnte ich die Höhe eines containerView abhängig von seinem Inhalt dynamisch machen:

Im ViewController des containerView schreiben Sie:

  override func loadView() {
    super.loadView()
    view.translatesAutoresizingMaskIntoConstraints = false
  }

Und darauf achten, dass die vertikalen Beschränkungen in IB alle gesetzt sind. Dazu müssen Sie view.translatesAutoresizingMaskIntoConstraints = false nicht außerhalb des View-Controllers festlegen.

In meinem Fall habe ich versucht, die Größe des Containers auf eine TableView im viewController zu ändern. Da das tableView abhängig von seinem Überblick eine flexible Höhe hat (also alles OK für IB), habe ich die vertikalen Einschränkungen im Code folgendermaßen ausgeführt:

  @IBOutlet private var tableView: UITableView! {
    didSet {
      tableView.addConstraint(tableViewHeight)
    }
  }
  private lazy var tableViewHeight: NSLayoutConstraint = NSLayoutConstraint(item: self.tableView, attribute: NSLayoutAttribute.Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1, constant: 0)

Beobachten Sie dann die contentSize-Höhe der TableView und passen Sie die Konstante der tableViewHeight-Einschränkung bei Bedarf programmgesteuert an.

20
acecilia

Swift 4, Xcode 9

Die akzeptierte Antwort alleine löste das Problem nicht für mich.

Meine Hierarchie: ScrollView -> Inhaltsansicht (UIView) -> Ansichten | Containeransicht | Weitere Ansichten.

Ich musste die folgenden Einschränkungen hinzufügen, um sowohl die Bildlaufansicht als auch den Container dynamisch anzupassen:

  1. ScrollView : Oben, Unten, Führen, Nach Übergehen (Sichere Bereiche)
  2. Inhaltsansicht : Oben, Unten, Führend, Nachlaufend, Gleiche Breite wie bei ScrollView, aber auch bei gleichen Höhen (Einschränkung mit niedrigerer Priorität: 250) .
  3. Ansichten : normale Einschränkungen für das automatische Layout.
  4. Containeransicht : Oben, Unten zu Nachbaransichten, Führen und Nachführen in den sicheren Bereich.
  5. Containeransicht eingebettet VC : Alles, was vertikal verbunden ist, wobei die untere Einschränkung auf eine niedrigere Priorität gesetzt ist,aber größer als die gleiche Höhe der Inhaltsansicht!In diesem Fall hatte eine Priorität von 500 den Trick.
  6. Setzen Sie view.translatesAutoresizingMaskIntoConstraints = false entweder in prepareForSegue() oder in loadView() als andere Antworten.

Jetzt habe ich eine dynamisch anpassbare Containeransicht in einer automatisch anpassbaren Bildlaufansicht.

12
Teodor Ciuraru

Aufbauend auf der großartigen Lösung von @ Mischa für dieses Problem müssen Sie, wenn der Container eine dynamisch dimensionierte UITableView einbettet, das Überschreiben von contentSize und intrinsicContentSize sowie das Festlegen von translatesAutoresizingMaskIntoConstraints = false Gemäß prüfen die akzeptierte Antwort.

Wenn die übergeordnete Ansicht die Containeransicht lädt und einrichtet, wird davon ausgegangen, dass die intrinsische Höhe der einzelnen UITableViewCells 0 ist, daher die UITableViewDelegate-Methode von:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell

wird nicht angerufen. Dadurch wird UITableView so angezeigt, als hätte es keinen Inhalt.

Durch das Überschreiben der inneren Inhaltsgröße, um die tatsächliche Inhaltsgröße zurückzugeben, wird die Tabellenansicht mit der Größe angezeigt, die der Inhalt benötigt.

Ein großer Artikel von Emilio Peláez vertieft dieses Thema.

2
Stuart Pattison