webentwicklung-frage-antwort-db.com.de

Programmgesteuertes Festlegen von Einschränkungen

Ich experimentiere mit der Verwendung von UIScrollView. Nach viel Mühe bekam ich endlich den Dreh raus. Aber jetzt scheine ich noch einen Haken zu haben.

In dieser einfachen App habe ich eine Bildlaufansicht mit und damit es funktioniert, muss ich den unteren Bereich der Ansicht auf 0 setzen, wie beschrieben hier und das funktioniert einwandfrei. Ich mache es durch die IB.

Jetzt bin ich auf ein Szenario gestoßen, in dem ich diesen Teil programmatisch ausführen muss. Ich habe den folgenden Code in der viewDidLoad -Methode hinzugefügt.

NSLayoutConstraint *bottomSpaceConstraint = [NSLayoutConstraint constraintWithItem:self.view
                                                                             attribute:NSLayoutAttributeBottom
                                                                             relatedBy:NSLayoutRelationEqual
                                                                                toItem:self.scrollView
                                                                             attribute:NSLayoutAttributeBottom
                                                                            multiplier:1.0
                                                                              constant:0.0];
[self.view addConstraint:bottomSpaceConstraint];

Aber es scheint nicht zu funktionieren. Es gibt die folgende Meldung im Konsolenfenster aus und ich weiß nicht, was ich daraus machen soll.

Bedingungen können nicht gleichzeitig erfüllt werden. Möglicherweise ist mindestens eine der Einschränkungen in der folgenden Liste eine, die Sie nicht möchten. Versuchen Sie Folgendes: (1) Sehen Sie sich jede Einschränkung an und versuchen Sie herauszufinden, was Sie nicht erwarten. (2) Finden Sie den Code, der die unerwünschte (n) Einschränkung (en) hinzugefügt hat, und korrigieren Sie ihn. (Hinweis: Wenn Sie NSAutoresizingMaskLayoutConstraints sehen, die Sie nicht verstehen, lesen Sie die Dokumentation der UIView-Eigenschaft translatesAutoresizingMaskIntoConstraints.) ("", "")

Kann mir bitte jemand sagen, wie das geht? Ich habe auch ein Demo-Projekt angehängt hier , damit Sie eine bessere Vorstellung von dem Problem bekommen.

UPDATE:

Zunächst einmal danke für die Antworten. Mit den in den Antworten genannten Methoden konnte ich es zum Laufen bringen. In einem etwas anderen Szenario ist dies jedoch nicht der Fall. Jetzt versuche ich, eine Ansicht programmgesteuert auf einen Ansichtscontroller zu laden.

Wenn ich weiter erklären darf. Es gibt 2 View Controller. Das erste ist ein UITableViewController und das zweite ein UIViewController. Darin befindet sich ein UIScrollView. Es gibt auch mehrere UIViews und einige der Ansichten überschreiten die normale Höhe des Bildschirms.

Das UITableViewController zeigt eine Liste von Optionen an. Basierend auf der Auswahl des Benutzers wird ein bestimmtes UIView aus dem Los mit dem UIViewController in das UIScrollView geladen.

In diesem Szenario funktioniert die obige Methode nicht. Das Scrollen findet nicht statt. Muss ich etwas anderes tun, da ich die Ansicht separat lade?

Ich habe ein Demo-Projekt hochgeladen hier damit Sie es in Aktion sehen können. Bitte sehen Sie sich ... an Email.xib und wählen Sie E-Mail aus der Liste der Tabellenansichten.

26
Isuru

Basierend auf einer Überprüfung Ihres Codes, ein paar Kommentare:

  1. Im Allgemeinen müssen Sie keine Einschränkungen anpassen, wenn eine Ansicht angezeigt wird. Wenn Sie dies bemerken, bedeutet dies häufig, dass Sie Ihr Storyboard nicht richtig (oder zumindest nicht effizient) konfiguriert haben. Das einzige Mal, dass Sie wirklich Einschränkungen festlegen/erstellen müssen, ist entweder (a) Sie fügen Ansichten programmgesteuert hinzu (was meiner Meinung nach mehr Arbeit bedeutet, als es wert ist); oder (b) Sie müssen einige Laufzeitanpassungen von Einschränkungen vornehmen (siehe dritter Aufzählungspunkt unter Punkt 3 unten).

  2. Ich möchte es nicht näher erläutern, aber Ihr Projekt enthielt eine Menge redundanten Codes. Z.B.

    • Sie haben den Rahmen für die Bildlaufansicht festgelegt, dies wird jedoch von Einschränkungen bestimmt, sodass dies keine Auswirkungen hat (d. H., Wenn die Einschränkungen angewendet werden, werden alle manuell festgelegten frame -Einstellungen ersetzt). Versuchen Sie im Allgemeinen im automatischen Layout nicht, frame direkt zu ändern: Bearbeiten Sie die Einschränkungen. Es ist jedoch ohnehin keine Änderung der Einschränkungen erforderlich, daher ist der Punkt umstritten.

    • Sie haben die Inhaltsgröße für die Bildlaufansicht festgelegt, aber auch im automatischen Layout gelten Einschränkungen (für die Unteransichten), sodass dies nicht erforderlich war.

    • Sie haben Einschränkungen für die Bildlaufansicht festgelegt (die bereits Null waren), aber dann haben Sie die Ansicht von der NIB nicht in die Bildlaufansicht eingefügt, wodurch auch dort eine Absicht beseitigt wurde. Die ursprüngliche Frage war, wie die untere Einschränkung der Bildlaufansicht geändert werden kann. Die unterste Einschränkung dafür ist jedoch bereits Null, sodass ich keinen Grund sehe, sie erneut auf Null zu setzen.

  3. Ich würde eine radikalere Vereinfachung Ihres Projekts vorschlagen:

    • Sie machen sich das Leben viel schwerer, indem Sie Ihre Ansichten in NIBs speichern. Es ist viel einfacher, in der Storyboard-Welt zu bleiben. Wir können Ihnen helfen, das NIB-Zeug zu machen, wenn Sie es wirklich brauchen, aber warum sollten Sie sich das Leben so schwer machen?

    • Verwenden Sie Zellprototypen, um die Gestaltung der Zellen in Ihrer Tabelle zu erleichtern. Sie können auch die Segmente definieren, die von den Zellen zur nächsten Szene wechseln sollen. Dadurch entfällt die Notwendigkeit, didSelectRowAtIndexPath oder prepareForSegue Code zu schreiben. Wenn Sie etwas haben, das Sie an die nächste Szene weitergeben müssen, verwenden Sie auf jeden Fall prepareForSegue, aber nichts, was Sie bisher präsentiert haben, erfordert dies. Deshalb habe ich es in meinen Beispielen auskommentiert.

    • Angenommen, Sie suchten nach einem praktischen Beispiel für die programmgesteuerte Änderung von Einschränkungen. Ich habe die Szene so eingerichtet, dass die Textansicht ihre Höhe programmgesteuert ändert, basierend auf dem Text in der Textansicht. Wie immer ist es meiner Meinung nach weitaus effizienter, eine IBOutlet für die Einschränkung einzurichten und die zu bearbeiten, als die betreffenden Einschränkungen zu durchlaufen, um die fragliche zu finden constant -Eigenschaft für die Einschränkung direkt, also habe ich das getan. Also habe ich den Ansichtscontroller als Stellvertreter der Textansicht eingerichtet und ein textViewDidChange geschrieben, das die Höhenbeschränkung der Textansicht aktualisiert:

      #pragma mark - UITextViewDelegate
      
      - (void)textViewDidChange:(UITextView *)textView
      {
          self.textViewHeightConstraint.constant = textView.contentSize.height;
          [self.scrollView layoutIfNeeded];
      }
      

      Beachten Sie, dass meine Textansicht zwei Höhenbeschränkungen hat, eine obligatorische Mindesthöhenbeschränkung und eine Einschränkung mittlerer Priorität, die ich oben basierend auf der Textmenge ändere. Der Hauptpunkt ist, dass es ein praktisches Beispiel für die programmgesteuerte Änderung von Einschränkungen darstellt. Sie sollten sich nicht mit der untersten Einschränkung der Bildlaufansicht herumschlagen müssen, aber dies ist ein reales Beispiel dafür, wann Sie eine Einschränkung anpassen möchten.


Wenn Sie eine Bildlaufansicht in IB hinzufügen, werden automatisch alle erforderlichen Einschränkungen abgerufen. Sie möchten wahrscheinlich keine Einschränkung programmgesteuert hinzufügen (zumindest nicht, ohne die vorhandene untere Einschränkung zu entfernen).

Zwei Ansätze könnten einfacher sein:

  1. Erstellen Sie ein IBOutlet für Ihre vorhandene untere Einschränkung, sagen Sie scrollViewBottomConstraint. Dann kannst du einfach machen

    self.scrollViewBottomConstraint.constant = 0.0;
    
  2. Oder erstellen Sie Ihre Ansicht zunächst in IB, wobei die unterste Einschränkung 0.0 ist und Sie dann überhaupt nichts programmgesteuert tun müssen. Wenn Sie eine lange Bildlaufansicht und ihre Unteransichten gestalten möchten, wählen Sie den Controller aus und stellen Sie die simulierten Metriken von "abgeleitet" auf "freie Form" ein. Dann können Sie die Größe der Ansicht ändern, die Ober- und Untergrenze der Bildlaufansicht auf Null setzen, alle gewünschten Layouts in der Bildlaufansicht erstellen und die Ansicht dann, wenn sie zur Laufzeit angezeigt wird, die Größe entsprechend anpassen Haben Sie für die obere und untere Einschränkung der Bildlaufansicht den Wert 0,0 festgelegt, wird die Größe ordnungsgemäß geändert. Es sieht in IB etwas seltsam aus, aber es funktioniert wie ein Zauber, wenn die App ausgeführt wird.

  3. Wenn Sie entschlossen sind, eine neue Einschränkung hinzuzufügen, können Sie entweder die alte untere Einschränkung programmgesteuert entfernen oder die Priorität der alten unteren Einschränkung so niedrig wie möglich einstellen. Auf diese Weise hat Ihre neue Einschränkung (mit höherer Priorität) Vorrang. und die alte untere Einschränkung mit niedriger Priorität wird ordnungsgemäß nicht angewendet.

Aber Sie möchten auf keinen Fall einfach eine neue Einschränkung hinzufügen.

56
Rob

Es ist möglich, Outlets zu erstellen, um Layoutbeschränkungen in Ihrem View-Controller darzustellen. Wählen Sie einfach die gewünschte Einschränkung im Interface Builder aus (z. B. über "Auswählen und Bearbeiten" im Messbereich der Ansicht, die Sie anordnen). Wechseln Sie dann in den Outlets-Bereich und ziehen Sie ein "New Referencing Outlet" in Ihre Codedatei (.h oder .m). Dadurch wird die Einschränkung an eine Instanz von NSLayoutConstraint gebunden, auf die Sie von Ihrem Controller aus zugreifen und die Sie dynamisch anpassen können (im Allgemeinen über die Eigenschaft constant, die einen schlechten Namen hat, weil sie überhaupt keine Konstante ist) ).

enter image description here

(Beachten Sie, dass Sie in XCode 6 auf die Einschränkung doppelklicken können, um sie zur Bearbeitung auszuwählen.)

enter image description here

Seien Sie jedoch vorsichtig, wenn Sie das Layout im Interface Builder anpassen, da Sie die Einschränkung möglicherweise löschen und sie erneut an den Ausgang binden müssen.

21
devios1

Wenn Sie sich die Konsoleninformationen ansehen, haben Sie das Gefühl, dass Sie Mehrdeutigkeiten schaffen, wenn Sie zwei gleiche Arten von Einschränkungen hinzufügen.

Versuchen Sie also, anstatt eine neue Einschränkung zu erstellen und hinzuzufügen, die vorherige Einschränkung zu aktualisieren, die sich bereits im Einschränkungsarray befindet.

for(NSLayoutConstraint *constraint in self.view.constraints)
    {
        if(constraint.firstAttribute == NSLayoutAttributeBottom && constraint.secondAttribute == NSLayoutAttributeBottom &&
           constraint.firstItem == self.view && constraint.secondItem == self.scrollView)
        {
            constraint.constant = 0.0;
        }
    }

Hoffe das hilft

Sogar Robs Antwort wird funktionieren!

12
Kunal

Sie können https://github.com/SnapKit/Masonry zum programmgesteuerten Hinzufügen von Einschränkungen verwenden.

Es ist die Stärke von AutoLayout NSLayoutConstraints mit einer vereinfachten, verkettbaren und aussagekräftigen Syntax. Unterstützt iOS und OSX Auto Layout.

UIView *superview = self.view;

UIView *view1 = [[UIView alloc] init];
view1.translatesAutoresizingMaskIntoConstraints = NO;
view1.backgroundColor = [UIColor greenColor];
[superview addSubview:view1];

UIEdgeInsets padding = UIEdgeInsetsMake(10, 10, 10, 10);

[superview addConstraints:@[
//view1 constraints
[NSLayoutConstraint constraintWithItem:view1
                             attribute:NSLayoutAttributeTop
                             relatedBy:NSLayoutRelationEqual
                                toItem:superview
                             attribute:NSLayoutAttributeTop
                            multiplier:1.0
                              constant:padding.top],

[NSLayoutConstraint constraintWithItem:view1
                             attribute:NSLayoutAttributeLeft
                             relatedBy:NSLayoutRelationEqual
                                toItem:superview
                             attribute:NSLayoutAttributeLeft
                            multiplier:1.0
                              constant:padding.left],

[NSLayoutConstraint constraintWithItem:view1
                             attribute:NSLayoutAttributeBottom
                             relatedBy:NSLayoutRelationEqual
                                toItem:superview
                             attribute:NSLayoutAttributeBottom
                            multiplier:1.0
                              constant:-padding.bottom],

[NSLayoutConstraint constraintWithItem:view1
                             attribute:NSLayoutAttributeRight
                             relatedBy:NSLayoutRelationEqual
                                toItem:superview
                             attribute:NSLayoutAttributeRight
                            multiplier:1
                              constant:-padding.right],]];

in wenigen Zeilen

Hier sind die gleichen Einschränkungen, die mit MASConstraintMaker erstellt wurden

UIEdgeInsets padding = UIEdgeInsetsMake(10, 10, 10, 10);

[view1 mas_makeConstraints:^(MASConstraintMaker *make) {
    make.top.equalTo(superview.mas_top).with.offset(padding.top); //with is an optional semantic filler
    make.left.equalTo(superview.mas_left).with.offset(padding.left);
    make.bottom.equalTo(superview.mas_bottom).with.offset(-padding.bottom);
    make.right.equalTo(superview.mas_right).with.offset(-padding.right);
}];

Oder noch kürzer

[view1 mas_makeConstraints:^(MASConstraintMaker *make) {
    make.edges.equalTo(superview).with.insets(padding);
}];

mach dein bestes ist sort;)

2
ERbittuu