Kann ich das Autolayout für eine bestimmte Unteransicht zur Laufzeit deaktivieren?

104

Ich habe eine Ansicht, deren Rahmen programmgesteuert bearbeitet werden muss - es ist eine Art Dokumentansicht, die den Inhalt umschließt und dann durch Bearbeiten des Rahmenursprungs durch eine Übersicht gescrollt und gezoomt wird. Autolayout kämpft zur Laufzeit damit.

Das vollständige Deaktivieren des automatischen Layouts scheint etwas schwierig zu sein, da es vernünftigerweise verwendet werden kann, um das Layout für die anderen Ansichten zu verwalten. Es scheint, als ob ich eine Art "Null-Einschränkung" haben möchte.

Terriblememory
quelle

Antworten:

168

Ich hatte das gleiche Problem. Aber ich habe es gelöst.
Ja, Sie können das automatische Layout zur Laufzeit für eine bestimmte UIViewVersion deaktivieren, anstatt es für das gesamte XIB oder Storyboard zu deaktivieren, das in Xcode 4.3 und höher standardmäßig festgelegt ist.

Setzen Sie translatesAutoresizingMaskIntoConstraintsauf YES, bevor Sie den Rahmen Ihres subview gesetzt:

self.exampleView.translatesAutoresizingMaskIntoConstraints = YES;
self.exampleView.frame = CGRectMake(20, 20, 50, 50);
Muhammad Aamir Ali
quelle
2
Dies sieht für einige kompliziertere Fälle mit vielen Ansichten wie ein Overkill aus. Für so etwas Einfaches ist das in Ordnung.
Esh
@MuhammadAamirALi Unteransicht entfernen und dann wieder hinzufügen kann die Leistung verringern. Können wir eine bessere Lösung archivieren?
Nhat Dinh
2
@ DinhNhat ich die Antwort geklärt. Das Entfernen und erneute Hinzufügen der Unteransicht ist nicht erforderlich.
Leandros
5
Es zeigt mir die Warnung: "Einschränkungen können nicht gleichzeitig erfüllt werden."
NSPratik
1
Du hast meinen Tag gerettet ... übersetztAutoresizingMaskIntoConstraints ... wer erfindet Eigenschaften wie dieses Schüttelkopf
Tintenklecks
50

Ich hatte ein ähnliches Problem, bei dem Autolayout einige meiner Frame-Einstellungen zur Laufzeit überschrieb (ich hatte eine dynamische Ansicht, die in einigen Fällen einen neuen Ansichts-Controller drückte ... Durch Drücken und anschließendes Drücken von Zurück wurde die ursprüngliche Ansicht zurückgesetzt).

Ich habe dies umgangen, indem ich meinen Manipulationscode in viewDidLayoutSubviewsmeinen View Controller eingegeben habe. Dies scheint aufgerufen zu werden, nachdem die Einschränkung mojo aufgerufen wurde, jedoch vor viewDidAppear, sodass der Benutzer nicht klüger ist.

jmstone617
quelle
1
Funktioniert nicht für self.navigationItem.titleView. Respektiert den Frame-Wechsel immer noch nicht.
Henrik Erlandsson
1
Wenn Sie versuchen, mit dem Rahmen einer Titelansicht zu spielen, würde ich ihn in eine Containeransicht einfügen und die Containeransicht als benutzerdefinierte Ansicht des Navigationselements hinzufügen.
jmstone617
2
Das hat auch bei mir funktioniert. Ich hatte 2h: 22m damit verschwendet, meinen Kopf gegen die sprichwörtliche Wand zu schlagen, bevor ich diese Problemumgehung entdeckte.
TMc
Danke, Mann. Ich habe an meinem zweiten Tag mit diesem Problem zu kämpfen und jetzt funktioniert es!
Apostolow
28

Vielleicht Einstellung nur translatesAutoresizingMaskIntoConstraintszu YES(und nicht zusätzliche Einschränkungen Hinzufügen dieser Ansicht zu beeinflussen) lassen Sie den Rahmen gesetzt , ohne das Auto - Layout - System zu kämpfen.

Jon Hull
quelle
17

In iOS 8 können Sie eine NSLayoutConstraint so einstellen, dass sie aktiv ist oder nicht. Wenn ich also den Interface Builder verwende, füge ich alle meine Einschränkungen einer OutletCollection hinzu und aktiviere oder deaktiviere sie dann mit:

NSLayoutConstraint.deactivateConstraints(self.landscapeConstraintsPad)
NSLayoutConstraint.activateConstraints(self.portraitConstraintsPad)

Die spezielle Anwendung, für die ich sie hier verwende, hat unterschiedliche Einschränkungen im Hoch- und Querformat und ich aktiviere / deaktiviere sie basierend auf der Drehung des Geräts. Dies bedeutet, dass ich einige komplexe Layoutänderungen im Interface Builder für beide Ausrichtungen erstellen und trotzdem das automatische Layout ohne den ausführlichen automatischen Layoutcode verwenden kann.

Oder Sie können mit removeConstraints und addConstraints aktivieren / deaktivieren.

Bandejapaisa
quelle
Es tut mir leid, dass Sie eine so alte Frage entführt haben, aber darf ich fragen, wie Sie es überhaupt geschafft haben, Layoutbeschränkungen für verschiedene Layouts hinzuzufügen? Ich kann anscheinend keine Option im Interface Builder finden, um Einschränkungen zu aktivieren / deaktivieren. Oder haben Sie einfach Einschränkungen für beide Layouts hinzugefügt und den Interface Builder einfach ignoriert, der sich über ungültige (überschreibende) Einschränkungen beschwert?
Malte
Nun, Sie könnten es mit Größenklassen tun: developer.apple.com/library/ios/recipes/… , aber ich konnte es nicht so machen, weil ich auch iOS 7 unterstützte und Größenklassen iOS 7 nicht vollständig unterstützen Ich habe es getan, indem ich die Priorität der widersprüchlichen Einschränkung gesenkt habe. Nicht ideal, aber es verhindert die Warnung. Ich denke, so habe ich es trotzdem gemacht ...
Bandejapaisa
9

Ich weiß nicht, ob dies jemand anderem helfen wird, aber ich habe eine Kategorie geschrieben, um dies zu vereinfachen, da ich dies häufig tue.

UIView + DisableAutolayoutTemporARY.h

#import <UIKit/UIKit.h>

@interface UIView (DisableAutolayoutTemporarily)

// the view as a parameter is a convenience so we don't have to always
// guard against strong-reference cycles
- (void)resizeWithBlock:(void (^)(UIView *view))block;

@end

UIView + DisableAutolayoutTemporARY.m

#import "UIView+DisableAutoResizeTemporarily.h"
@implementation UIView (DisableAutoResizeTemporarily)

- (void)resizeWithBlock:(void (^)(UIView * view))block
{
    UIView *superview = self.superview;
    [self removeFromSuperview];
    [self setTranslatesAutoresizingMaskIntoConstraints:YES];
    __weak UIView *weakSelf = self;
    block(weakSelf);
    [superview addSubview:self];
}

@end

Ich benutze es so:

[cell.argumentLabel resizeWithBlock:^(UIView *view) {
    [view setFrame:frame];
}];

Ich hoffe es hilft.

michaelsnowden
quelle
Brillant ! Ich habe eine modifizierte Version Ihres Codes verwendet, um eine einfache "hideControl" -Funktion für jedes UIView zu schreiben. Grundsätzlich wird die Höhe eines UIView auf 0 gesetzt, aber entscheidend ist, dass Ihr Code verwendet wird, damit AutoLayout richtig damit umgeht (im Gegensatz zur Verwendung von "someView.hidden = TRUE"). Steuerelemente, die unterhalb des verborgenen Steuerelements angezeigt wurden und mit denen ein vertikaler Abstand verknüpft war, wurden nun auf dem Bildschirm nach oben verschoben, um die Lücke zu füllen, in der zuvor die verborgene Ansicht angezeigt wurde.
Mike Gledhill
6

Sie können den translatesAutoresizingMaskIntoConstraintsTyp BooleanWert Ja in den benutzerdefinierten Laufzeitattributen der gewünschten UIView im xib / storyboard festlegen.

Renaun
quelle
2
  • Öffnen Sie das Projekt in 4.5
  • Storyboard auswählen
  • Öffnen Sie den Dateiinspektor
  • Deaktivieren Sie unter Interface Builder-Dokument das Kontrollkästchen "Autolayout verwenden".

Sie können sich auf mehrere Storyboards aufteilen, wenn Sie für einige Ansichten das automatische Layout verwenden möchten.

Mike Bobbitt
quelle
10
Dadurch wird das automatische Layout für das gesamte Storyboard / die gesamte Feder deaktiviert. Was ich suchte, war eine Möglichkeit (idealerweise programmatisch), bestimmte Unteransichten innerhalb eines Storyboards / einer Schreibfeder zu verwenden, ohne das Autolayout zu verwenden, während der Rest das tun ließ, was auch immer das Storyboard / die Schreibfeder spezifizierte.
Terriblememory
Sie können mehrere Storyboards verwenden und nach Bedarf diejenigen mit / ohne Autolayout aufrufen: // Initialisieren Sie den Storboard- und Detailansichts-Controller für die Anzeige. UIStoryboard * sb = [UIStoryboard storyboardWithName: @ "Storyboard" -Paket: [NSBundle mainBundle]]; DetailViewController * dvController = [sb instantiateViewControllerWithIdentifier: entry.viewName];
Mike Bobbitt
1

Für mich hat es funktioniert, die Unteransicht programmgesteuert zu erstellen. In meinem Fall hat das automatische Layout eine Ansicht durcheinander gebracht, die ich um die Mitte drehen musste, aber nachdem ich diese Ansicht programmgesteuert erstellt habe, hat es funktioniert.

Andrespch
quelle
1

Aus meiner Sicht hatte ich ein Etikett und einen Text. Das Etikett hatte eine Schwenkgeste. Das Etikett bewegt sich beim Ziehen gut. Wenn ich jedoch die Textfeldtastatur verwende, setzt das Etikett seine Position auf die ursprüngliche Position zurück, die im automatischen Layout definiert ist. Das Problem wurde behoben, als ich schnell Folgendes für das Etikett hinzufügte. Ich habe dies in viewWillAppear hinzugefügt, aber es kann praktisch überall dort hinzugefügt werden, wo Sie Zugriff auf das Zielfeld haben.

self.captionUILabel.translatesAutoresizingMaskIntoConstraints = true
Großes D
quelle
0

Dies ist mir in einem Projekt ohne Storyboards oder XIB-Dateien passiert. Alle 100% Code. Ich hatte unten ein Werbebanner und wollte, dass die Ansichtsgrenzen beim Werbebanner anhalten. Die Größe der Ansicht wird nach dem Laden automatisch geändert. Ich habe jede Auflösung auf dieser Seite ausprobiert, aber keine davon hat funktioniert.

Am Ende habe ich nur eine Unteransicht mit der verkürzten Höhe erstellt und diese in die Hauptansicht des Controllers eingefügt. Dann ging mein gesamter Inhalt in die Unteransicht. Das löste das Problem sehr leicht, ohne etwas zu tun, das sich gegen den Strich anfühlte.

Ich denke, wenn Sie eine Ansicht wünschen, die nicht die normale Größe hat, die das Fenster ausfüllt, sollten Sie dafür eine Unteransicht verwenden.

RandallTo
quelle
0

Ich bin auf ein ähnliches Szenario gestoßen, in dem ich einem Projekt beigetreten bin, das mit automatischem Layout initiiert wurde, aber ich musste mehrere Ansichten dynamisch anpassen. Folgendes hat bei mir funktioniert:

  1. Lassen Sie KEINE Ansichten oder Komponenten im Interface Builder anlegen.

  2. Fügen Sie Ihre Ansichten rein programmgesteuert hinzu, indem Sie mit alloc / init beginnen und ihre Frames entsprechend einstellen.

  3. Getan.

Jep.
quelle
0

Anstatt das automatische Layout zu deaktivieren, würde ich nur die neue Einschränkung mit dem Frame berechnen, den Sie ersetzen. Das scheint mir der richtige Weg zu sein. Wenn Sie Komponenten anpassen, die auf Einschränkungen beruhen, passen Sie sie entsprechend an.

Wenn Sie beispielsweise eine vertikale Einschränkung von 0 zwischen zwei Ansichten (myView und otherView) haben und eine Schwenkgeste oder etwas haben, das die Höhe von myView anpasst, können Sie die Einschränkung mit den angepassten Werten neu berechnen.

self.verticalConstraint.constant = newMyViewYOriginValue - (self.otherView.frame.origin.y + self.otherView.frame.size.height);
[self.myView needsUpdateConstraints];
Myles Caley
quelle
0

Für diejenigen unter Ihnen, die das automatische Layout verwenden, sehen Sie sich bitte meine Lösung hier an . Sie sollten @IBOutletdie Einschränkungen festlegen, die Sie anpassen möchten, und dann deren Konstanten ändern.

Mike
quelle
-16

Wenn es sich um eine XIB-Datei handelt:

  1. Wählen Sie die .xib-Datei aus
  2. Wählen Sie den "Eigentümer der Datei".
  3. Zeigen Sie die Dienstprogramme an
  4. Klicken Sie auf: "File Inspector"
  5. Deaktivieren Sie unter "Interface Builder-Dokument": "Autolayout verwenden"
Alish
quelle
1
Nein, das deaktiviert das Autolayout für die gesamte xib. Was ich gesucht habe, ist eine Möglichkeit, nur eine bestimmte Unteransicht aus dem Autolayout-System zu entfernen.
Terriblememory