2013-05-28 4 views
7

Ich habe einen View-Controller, der eine einzelne benutzerdefinierte Ansicht besitzt; Die benutzerdefinierte Ansicht zeichnet ein Spielbrett mit Core Graphics. (Keine anderen Subviews sind involviert.)Warum verkleinert sich meine Superview mit Subview, wenn sie modal präsentiert wird (mit Auto Layout)?

Ich richte Auto-Layout-Einschränkungen ein, damit das Spielbrett seine Superansicht füllt. Wenn ich den View-Controller als Root-View-Controller einstelle, füllt das Spielbrett (und Superview) den Bildschirm, wie es meine Absicht ist. Wenn ich jedoch den View-Controller modal präsentiere, verkleinert sich das Spielbrett (und Superview) auf nichts/Minimum, und die Auto-Layout-Ablaufverfolgung meldet, dass das Layout mehrdeutig ist.

Ich schrieb einen vereinfachten Testfall, um die Frage zu veranschaulichen.

Hier ist meine BoardViewController, die eine Top-Level-Ansicht mit einem grünen Hintergrund hat, aber eine einzelne expansive Subview mit einem roten Hintergrund erstellt. Ich mag den Bildschirm all rot sehen, wenn diese Ansicht-Controller übernehmen:

- (void)loadView 
{ 
    UIView *mainView = [[UIView alloc] init]; 
    mainView.translatesAutoresizingMaskIntoConstraints = NO; 
    mainView.backgroundColor = [UIColor greenColor]; 

    UIView *subView = [[UIView alloc] init]; 
    subView.translatesAutoresizingMaskIntoConstraints = NO; 
    subView.backgroundColor = [UIColor redColor]; 

    [mainView addSubview:subView]; 
    self.view = mainView; 

    NSDictionary *viewsDictionary = NSDictionaryOfVariableBindings(subView); 
    NSArray *c1 = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[subView(>=10)]|" 
                 options:0 
                 metrics:nil 
                  views:viewsDictionary]; 
    NSArray *c2 = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|[subView(>=10)]|" 
                 options:0 
                 metrics:nil 
                  views:viewsDictionary]; 
    [self.view addConstraints:c1]; 
    [self.view addConstraints:c2]; 
} 

Wenn ich das als meine root-View-Controller gesetzt, dann habe ich mein schönes rotes Spielbrett zu sehen füllt den Bildschirm. Allerdings schrumpft das Spielbrett auf das Minimum 10x10 Platz, wenn ich die BoardViewController aus einer anderen RootViewController präsentieren:

- (void)loadView 
{ 
    UIView *rootView = [[UIView alloc] init]; 
    rootView.translatesAutoresizingMaskIntoConstraints = NO; 

    UIButton *presentButton = [UIButton buttonWithType:UIButtonTypeRoundedRect]; 
    presentButton.translatesAutoresizingMaskIntoConstraints = NO; 
    [presentButton setTitle:@"Present" forState:UIControlStateNormal]; 
    [presentButton addTarget:self 
        action:@selector(present:) 
      forControlEvents:UIControlEventTouchUpInside]; 

    [rootView addSubview:presentButton]; 
    self.view = rootView; 

    [rootView addConstraint:[NSLayoutConstraint constraintWithItem:presentButton 
                 attribute:NSLayoutAttributeCenterX 
                 relatedBy:NSLayoutRelationEqual 
                  toItem:rootView 
                 attribute:NSLayoutAttributeCenterX 
                 multiplier:1.0 
                 constant:0.0]]; 
    [rootView addConstraint:[NSLayoutConstraint constraintWithItem:presentButton 
                 attribute:NSLayoutAttributeCenterY 
                 relatedBy:NSLayoutRelationEqual 
                  toItem:rootView 
                  attribute:NSLayoutAttributeCenterY 
                 multiplier:1.0 
                 constant:0.0]]; 
} 

- (void)present:(id)sender 
{ 
    BoardViewController *bvc = [[BoardViewController alloc] init]; 
    [self presentViewController:bvc animated:YES completion:NULL]; 
} 

ich verschiedene Auto-Layout-Regeln immer wieder versuchen, aber egal was ich tue, ich kann das Spiel nicht bekommen Board, um den Bildschirm zu füllen, wenn der View-Controller modal präsentiert wird. (Zur gleichen Zeit, die ich diese Frage stelle, versuche ich, die Laufzeit zu erhalten, um mir zu sagen, was es denkt, ist mehrdeutig. Aber ich bin nicht sehr gut dieses Debuggen noch, daher meine Frage hier.)

Antwort

2

entfernen:

mainView.translatesAutoresizingMaskIntoConstraints = NO;

Es ist interessant, dass dies funktioniert. Es impliziert, dass, wenn die Ansicht modal presentViewController mit präsentiert wird es Einschränkungen haben, wird erwartet, dass es auf seine Superview, die nun aber, wenn sie als rootViewController eines UIWindow setzen sie sie nicht brauchen ...

+0

Brilliant! Vielen Dank! Also, Erklärung: Ich habe irrigerweise mit dem Layout meiner Top-Level-Ansicht, die der Bereich von wem auch immer mich darstellt, falsch gemacht. In diesem Fall fügt 'presentViewController: animate: completion:' (wir nehmen an) seine Ansichten mithilfe von Springs-and-Struts hinzu, also habe ich es abgebrochen. Ist das eine faire Art, es zu sagen? –

+0

Aus dem, was ich sehen kann, scheint es, dass das 'rootViewController' eines Fensters ein spezieller Fall ist, der Einschränkungen umgeht.Es wäre interessant zu experimentieren mit dem, was passieren würde, wenn man 'mainView.translationsAutoresizingMaskIntoConstraints = NO;' verlässt und 'updateConstraints' implementiert, um einige Einschränkungen manuell hinzuzufügen ... –

+0

Ich habe versucht, den Wert von '[self.view translateAutoresizingMaskIntoConstraints]' zu verwerfen bei 'viewDidAppear:' für die modale Darstellung und das Setzen als Root-View-Controller. In beiden Fällen hat es JA verschenkt. Vielleicht legt das Setzen einer Ansicht als root-View-Controller explizit seinen Frame fest, während das Darstellen eines View-Controllers dies nicht tut. –

2

Nach einigen Untersuchungen, es sieht Wenn Sie beispielsweise einen Vollbildmodus für Modalansicht-Controller drücken und die Animation abgeschlossen ist, wird der Präsentationsansicht-Controller zusammen mit seiner Ansicht aus der Ansichtshierarchie entfernt. Wie erwartet werden die Views-Constraints dann entfernt. Sobald Sie den Modalansicht-Controller schließen, wird der ursprüngliche Viewcontroller mit seiner Ansicht wieder angezeigt, aber die Einschränkungen sind weg und wurden vom System nicht gespeichert und wiederhergestellt. Das ist ein Fehler. Sogar auf iOS7. Der Grund für die Verwendung von NSAutoresizingConstraints besteht darin, dass das Ansichtssystem die Einschränkungen selbst wiederherstellen kann. Wenn Sie ein Setup mit verschachtelten viewControllern haben (z. B. ein äußerer Viewcontroller bettet einen Navigationscontroller ein), können Sie diese mit dem Muster child viewcontrollers verknüpfen.

Wenn Sie dies getan haben, wird die oberste viewController-Ansicht durch das, was ich oben beschrieben habe, entfernt. Dies bedeutet, dass Sie den NSAutoresizingConstraints-Patch nur auf den obersten viewcontroller (in der Regel den Windows-root-viewcontroller) anwenden und Standardbedingungen verwenden müssen.