Programmgesteuertes Erstellen von Layouteinschränkungen

84

Ich weiß, dass viele Leute bereits Unmengen von Fragen dazu gestellt haben, aber selbst mit den Antworten kann ich es nicht zum Laufen bringen.

Wenn ich mich mit Einschränkungen im Storyboard beschäftige, ist es einfach, aber im Code fällt es mir schwer. Ich versuche zum Beispiel, eine Ansicht zu haben, die auf der rechten Seite bleibt und die Höhe des Bildschirms entsprechend der Bildschirmausrichtung hat. Das ist mein Code:

UIView *myView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 200, 748)];
myView.backgroundColor = [UIColor redColor];
[self.view addSubview:myView];
[self.view addConstraints:[NSLayoutConstraint
    constraintsWithVisualFormat:@"V:|-[myView(>=748)]-|"
    options:0 metrics:nil
    views:NSDictionaryOfVariableBindings(myView)]];

Es erfüllt einige Einschränkungen nicht. Ich sehe nicht, was los ist. Warum kann ich eine Eigenschaft wie nicht self.myViewanstelle einer lokalen Variablen wie verwenden myView?

pierre23
quelle
Was ist vivi im obigen Code?
iDev
14
Bitte ändern Sie den Titel in "iOS" anstelle von "IOS". Letzteres bezieht sich auf das Switch / Router-Betriebssystem von Cisco. Hat mich verwirrt. Vielen Dank.
Armani
1
Einige Fragen dazu: (1) Welchen Fehler erhalten Sie, wenn er "einige Einschränkungen nicht erfüllt"? (2) Übersetzen Sie die automatische Größenänderung in Einschränkungen für myView? (3) Was ist vivi(wie ACB gefragt hat)? (4) Haben Sie eine Immobilie myViewangemeldet self?
Tim
1
ih Tim, tut mir leid, die Vivi, ich habe zu schnell getippt ... es ist myView. Was meinst du mit übersetzen? Alles was ich mache ist auf dem obigen Code. Über die Eigenschaft habe ich einige andere Ansichten, die als Eigenschaft deklariert sind, aber wenn ich den gleichen Code für diese Eigenschaft implementiere, stürzt sie ab ... die Meldung "Fehler" ist wirklich groß, ich kann sie hier nicht einfügen
pierre23
Um Einschränkungen vorübergehend aus einer bestimmten Ansicht zu entfernen, gehen Sie wie folgt vor
Sam B

Antworten:

106

Wenn Sie das automatische Layout im Code verwenden, bewirkt das Festlegen des Rahmens nichts. Die Tatsache, dass Sie in der obigen Ansicht eine Breite von 200 angegeben haben, bedeutet also nichts, wenn Sie Einschränkungen festlegen. Damit die Einschränkungsmenge einer Ansicht eindeutig ist, sind vier Dinge erforderlich: eine x-Position, eine y-Position, eine Breite und eine Höhe für einen bestimmten Zustand.

Derzeit haben Sie im obigen Code nur zwei (Höhe relativ zur Übersicht und y-Position relativ zur Übersicht). Darüber hinaus sind zwei Einschränkungen erforderlich, die je nach Einrichtung der Einschränkungen der Übersicht der Ansicht zu Konflikten führen können. Wenn für die Übersicht eine erforderliche Einschränkung vorliegt, die angibt, dass die Höhe einen Wert von weniger als 748 aufweist, wird die Ausnahme "unbefriedigende Einschränkungen" angezeigt.

Die Tatsache, dass Sie die Breite der Ansicht festgelegt haben, bevor Sie Einschränkungen festlegen, bedeutet nichts. Es wird nicht einmal der alte Frame berücksichtigt und ein neuer Frame basierend auf allen Einschränkungen berechnet, die es für diese Ansichten angegeben hat. Wenn ich mich mit Autolayout im Code beschäftige, erstelle ich normalerweise einfach eine neue Ansicht mit initWithFrame:CGRectZerooder einfach init.

Um den Einschränkungssatz zu erstellen, der für das Layout erforderlich ist, das Sie in Ihrer Frage mündlich beschrieben haben, müssen Sie einige horizontale Einschränkungen hinzufügen, um die Breite und die x-Position zu begrenzen, um ein vollständig angegebenes Layout zu erhalten:

[self.view addConstraints:[NSLayoutConstraint
    constraintsWithVisualFormat:@"V:|-[myView(>=748)]-|"
    options:NSLayoutFormatDirectionLeadingToTrailing
    metrics:nil
    views:NSDictionaryOfVariableBindings(myView)]];

[self.view addConstraints:[NSLayoutConstraint
    constraintsWithVisualFormat:@"H:[myView(==200)]-|"
    options:NSLayoutFormatDirectionLeadingToTrailing
    metrics:nil
    views:NSDictionaryOfVariableBindings(myView)]];

Die verbale Beschreibung dieses Layouts lautet wie folgt, beginnend mit der vertikalen Einschränkung:

myView füllt die Höhe seiner Übersicht mit einer oberen und unteren Polsterung, die dem Standardbereich entspricht. Die Übersicht von myView hat eine Mindesthöhe von 748 Punkten. Die Breite von myView beträgt 200 Punkte und die rechte Auffüllung entspricht dem Standardbereich gegenüber der Übersicht.

Wenn Sie einfach möchten, dass die Ansicht die gesamte Höhe der Übersicht füllt, ohne die Höhe der Übersicht zu beschränken, lassen Sie den (>=748)Parameter im Text des visuellen Formats einfach weg . Wenn Sie der Meinung sind, dass der (>=748)Parameter erforderlich ist, um ihm eine Höhe zu geben, tun Sie dies in diesem Fall nicht: Befestigen Sie die Ansicht mit der Syntax bar ( |) oder bar mit der Leerzeichen- Syntax ( |-, -|) an den Rändern der Übersicht , geben Sie Ihrer Ansicht ein y -Position (Fixieren der Ansicht an einer einzelnen Kante) und eine y-Position mit Höhe (Fixieren der Ansicht an beiden Kanten), wodurch Ihre für die Ansicht festgelegte Einschränkung erfüllt wird.

In Bezug auf Ihre zweite Frage:

Mit NSDictionaryOfVariableBindings(self.myView)(wenn Sie eine Eigenschaft Setup für myView haben) und Fütterung , dass in Ihr VFL verwenden self.myViewin Ihrem VFL Text, werden Sie wahrscheinlich eine Ausnahme erhalten , wenn Automatisches Layout versucht Ihren VFL Text zu analysieren. Dies hängt mit der Punktnotation in den Wörterbuchschlüsseln und dem System zusammen, das versucht, sie zu verwenden valueForKeyPath:. Eine ähnliche Frage und Antwort finden Sie hier .

Larsacus
quelle
Vergessen Sie nicht, dass einige Objekte wie UILabel eine intrinsische Größe haben und Sie nicht die Breite oder Höhe dieses Objekts festlegen müssen, sondern nur seine Position. Wenn Sie jedoch die Höhe oder Breite einstellen, werden meiner Meinung nach beide entfernt, und Sie müssen dann beide angeben.
Nick Turner
Obwohl diese Antwort meine Frage nicht beantwortete, half sie mir, etwas zu realisieren. Danke fürs Sein! :)
Matej
1
Die einzige prägnante und lesbare Einführung in das automatische Layout im Internet.
Joey Carson
Bitte helfen Sie mir, meine Frage ist dies ... Ich weiß nicht, wie man Einschränkungen programmgesteuert verwendet. stackoverflow.com/questions/36326288/…
61

Hallo, ich habe diese Seite häufig für Einschränkungen und "How to" verwendet. Es dauerte ewig, bis mir klar wurde, dass ich Folgendes brauchte:

myView.translatesAutoresizingMaskIntoConstraints = NO;

um dieses Beispiel zum Laufen zu bringen. Vielen Dank an Userxxx, Rob M. und insbesondere Larsacus für die Erklärung und den Code hier, es war von unschätzbarem Wert.

Hier ist der vollständige Code, damit die obigen Beispiele ausgeführt werden können:

UIView *myView = [[UIView alloc] init];
myView.backgroundColor = [UIColor redColor];
myView.translatesAutoresizingMaskIntoConstraints = NO;  //This part hung me up 
[self.view addSubview:myView];
//needed to make smaller for iPhone 4 dev here, so >=200 instead of 748
[self.view addConstraints:[NSLayoutConstraint
                           constraintsWithVisualFormat:@"V:|-[myView(>=200)]-|"
                           options:NSLayoutFormatDirectionLeadingToTrailing
                           metrics:nil
                           views:NSDictionaryOfVariableBindings(myView)]];

[self.view addConstraints:[NSLayoutConstraint
                           constraintsWithVisualFormat:@"H:[myView(==200)]-|"
                           options:NSLayoutFormatDirectionLeadingToTrailing
                           metrics:nil
                           views:NSDictionaryOfVariableBindings(myView)]];
BriOnH
quelle
11

Schnelle Version

Aktualisiert für Swift 3

In diesem Beispiel werden zwei Methoden gezeigt, mit denen die folgenden Einschränkungen programmgesteuert hinzugefügt werden können, so wie dies im Interface Builder der Fall ist:

Breite und Höhe

Geben Sie hier die Bildbeschreibung ein

Im Container zentrieren

Geben Sie hier die Bildbeschreibung ein

Boilerplate-Code

override func viewDidLoad() {
    super.viewDidLoad()

    // set up the view
    let myView = UIView()
    myView.backgroundColor = UIColor.blue
    myView.translatesAutoresizingMaskIntoConstraints = false
    view.addSubview(myView)

    // Add constraints code here (choose one of the methods below)
    // ...
}

Methode 1: Ankerstil

// width and height
myView.widthAnchor.constraint(equalToConstant: 200).isActive = true
myView.heightAnchor.constraint(equalToConstant: 100).isActive = true

// center in container
myView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
myView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true

Methode 2: NSLayoutConstraint-Stil

// width and height
NSLayoutConstraint(item: myView, attribute: NSLayoutAttribute.width, relatedBy: NSLayoutRelation.equal, toItem: nil, attribute: NSLayoutAttribute.notAnAttribute, multiplier: 1, constant: 200).isActive = true
NSLayoutConstraint(item: myView, attribute: NSLayoutAttribute.height, relatedBy: NSLayoutRelation.equal, toItem: nil, attribute: NSLayoutAttribute.notAnAttribute, multiplier: 1, constant: 100).isActive = true

// center in container
NSLayoutConstraint(item: myView, attribute: NSLayoutAttribute.centerX, relatedBy: NSLayoutRelation.equal, toItem: view, attribute: NSLayoutAttribute.centerX, multiplier: 1, constant: 0).isActive = true
NSLayoutConstraint(item: myView, attribute: NSLayoutAttribute.centerY, relatedBy: NSLayoutRelation.equal, toItem: view, attribute: NSLayoutAttribute.centerY, multiplier: 1, constant: 0).isActive = true

Anmerkungen

  • Der Ankerstil ist die bevorzugte Methode gegenüber dem NSLayoutConstraintStil. Er ist jedoch nur unter iOS 9 verfügbar. Wenn Sie also iOS 8 unterstützen, sollten Sie weiterhin den NSLayoutConstraintStil verwenden.
  • Siehe auch die Dokumentation zum programmgesteuerten Erstellen von Einschränkungen .
  • In dieser Antwort finden Sie ein ähnliches Beispiel für das Hinzufügen einer Pinning-Einschränkung.
Suragch
quelle
5

In Bezug auf Ihre zweite Frage zu Eigenschaften können Sie diese self.myViewnur verwenden, wenn Sie sie als Eigenschaft in der Klasse deklariert haben. Da myViewes sich um eine lokale Variable handelt, können Sie sie nicht auf diese Weise verwenden. Für weitere Informationen hierzu empfehle ich Ihnen, die Apple-Dokumentation zu den deklarierten Eigenschaften zu lesen .

iDev
quelle
5

Warum kann ich keine Eigenschaft wie self.myViewanstelle einer lokalen Variablen wie myView verwenden?

versuchen Sie es mit:

NSDictionaryOfVariableBindings(_view)

anstatt self.view

Megarushing
quelle
Dadurch stürzt meine App ab und es wird die Meldung angezeigt: "Das Einschränkungsformat kann nicht analysiert werden: polylineImageView ist kein Schlüssel im Ansichtswörterbuch."
Tai Le
4

Bitte beachten Sie auch, dass wir ab iOS9 mithilfe von Unterklassen der neuen Hilfsklasse NSLayoutAnchor programmgesteuert Einschränkungen definieren können, die " präziser und leichter zu lesen" sind .

Ein Beispiel aus dem Dokument:

[self.cancelButton.leadingAnchor constraintEqualToAnchor:self.saveButton.trailingAnchor constant: 8.0].active = true;
andreacipriani
quelle