2010-07-12 7 views
20

So haben Sie einen Stapel mit drei View-Controllern, wobei A Root ist, B ist der erste modale View-Controller und C ist der dritte modale VC. Ich würde gerne von C nach A gehen. Ich habe versucht this solution to dismiss. Es tut Arbeit aber nicht in einer korrekten Weise. Das heißt, wenn der letzte View-Controller geschlossen wird, wird der zweite View-Controller kurz angezeigt, bevor der erste angezeigt wird. Wonach ich suche, ist eine Möglichkeit, in einer netten Animation vom dritten VC zum ersten zu kommen, ohne den zweiten Blick zu bemerken. Jede Hilfe dabei ist sehr geschätzt.Mehrere Modal-View-Controller gleichzeitig ausschließen?

+0

Eine allgemeinere Möglichkeit, mehr als einen modalen View-Controller zu verwerfen, ist [hier] (https://stackoverflow.com/a/44583711/1151916) – Ramis

Antwort

20

Achten Sie darauf, dass Sie nur einmal dismissModalViewControllerAnimated: anrufen.

Ich habe festgestellt, dass die Frage, jeden Stacked Modal View Controller zu entlassen, beide animieren wird.

Sie haben: A =modal> B =modal> C

Sie nur [myViewControllerA dismissModalViewControllerAnimated:YES]

nennen sollten Wenn Sie [myViewControllerB dismissModalViewControllerAnimated:YES] verwenden, wird es C entlassen, und nicht B. Im normalen (ungestapelt) verwenden, wäre es B zu entlassen (aufgrund der die Antwortkette sprudelt die Nachricht bis zu A). In dem gestapelten Szenario, das Sie beschreiben, handelt es sich um einen übergeordneten Ansichtscontroller, der Vorrang vor einem modalen Ansichtscontroller hat.

+7

Nun ab jetzt verwende ich: [[[self parentViewController] parentViewController] ablissModalViewControllerAnimated: YES]; Das würde den root viewcontroller verwenden. Es zeigt jedoch immer noch den zweiten VC für eine kurze Sekunde. – sebrock

+0

Oh, und ich sollte sagen, dass ich die Utility-Vorlage und die zweite vc ist die Rückseitenansicht verwenden. Der dritte ist ein modaler Vc, der von der Rückseite instanziiert wird. – sebrock

+1

HINWEIS: in iOS5 geändert zu "presentingViewController" http://game4mob.com/index.php/jawbreaker/66-dismiss-modal-view-in-ios5-sdk –

-5

Was Sie verwenden möchten, ist popToRootViewControllerAnimated:. Es bringt Sie zum Root-Controller, ohne alle dazwischenliegenden zu zeigen.

+1

Das ist eine großartige Lösung, wenn A die Wurzel eines 'UINavigationController' ist. – ohhorob

+1

Oh yeah. Ich bin gerade aufgewacht, also habe ich das nicht verstanden. – lucius

0

Sie können diese modalViewControllers an Ihrem rootViewController abweisen.

UIViewController *viewController = yourRootViewController; 

    NSMutableArray *array = [NSMutableArray array]; 
    while (viewController.modalViewController) { 
     [array addObject:viewController]; 
     viewController = viewController.modalViewController; 
    } 

    for (int i = 0; i < array.count; i++) { 
     UIViewController *viewController = array[array.count-1-i]; 
     [viewController dismissModalViewControllerAnimated:NO]; 
    } 
3

Obwohl die akzeptierte Antwort für mich arbeitet, kann es jetzt veraltet sein und hinterließ eine seltsam aussehende Animation, wo die obersten modalen sofort verschwinden würde und die Animation würde auf der Rückseite modalview sein. Ich habe viele Dinge ausprobiert, um das zu vermeiden, und musste am Ende ein bisschen hacken, damit es gut aussieht. Hinweis: (nur in iOS8 + getestet, sollte aber iOS7 + Arbeit)

Grundsätzlich schafft viewControllerA ein UINavigationController mit viewControllerB als RootView und präsentiert sie modal.

// ViewControllerA.m 
- (void)presentViewB { 
    ViewControllerB *viewControllerB = [[ViewControllerB alloc] init]; 
    UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:viewControllerB]; 

    navigationController.modalPresentationStyle = UIModalPresentationFormSheet; 
    [self presentViewController:navigationController animated:YES completion:nil]; 
} 

Jetzt in viewControllerB wir gehen viewControllerC die gleiche Art und Weise zu präsentieren, aber nachdem wir es präsentieren, werden wir einen Schnappschuss von viewControllerC über die View-Schicht auf viewControllerB ‚s Navigationssteuerung setzen. Dann, wenn viewControllerC während der Entlassung verschwindet, werden wir die Änderung nicht sehen und die Animation wird schön aussehen.

Im Folgenden sind meine Hilfsfunktionen, die verwendet werden, um die Ansicht zu präsentieren und zu entlassen. Eine Sache zu beachten, ich verwende Purelayout zum Hinzufügen von Auto-Layout-Einschränkungen. Sie können dies ändern, sie manuell hinzuzufügen oder zu erhalten Purelayout bei https://github.com/PureLayout/PureLayout

#pragma mark - Modal Presentation Helper functions 
- (void)presentViewControllerForModalDismissal:(UIViewController*)viewControllerToPresent { 
    UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:viewControllerToPresent]; 
    navigationController.modalPresentationStyle = UIModalPresentationFormSheet; 

    // Ensure that anything we are trying to present with this method has a dismissBlock since I don't want to force everything to inherit from some base class. 
    NSAssert([viewControllerToPresent respondsToSelector:NSSelectorFromString(@"dismissBlock")], @"ViewControllers presented through this function must have a dismissBlock property of type (void)(^)()"); 
    [viewControllerToPresent setValue:[self getDismissalBlock] forKey:@"dismissBlock"]; 

    [self presentViewController:navigationController animated:YES completion:^{ 
     // We want the presented view and this modal menu to dismiss simultaneous. The animation looks weird and immediately becomes the menu again when dismissing. 
     // So we are snapshotting the presented view and adding it as a subview so you won't see the menu again when dismissing. 
     UIView *snapshot = [navigationController.view snapshotViewAfterScreenUpdates:NO]; 
     [self.navigationController.view addSubview:snapshot]; 
     [snapshot autoPinEdgesToSuperviewEdges]; 
    }]; 
} 

- (void(^)()) getDismissalBlock { 
    __weak __typeof(self) weakSelf = self; 
    void(^dismissBlock)() = ^{ 
     __typeof(self) blockSafeSelf = weakSelf; 
     [blockSafeSelf.navigationController.presentingViewController dismissViewControllerAnimated:YES completion:nil]; 
    }; 

    return dismissBlock; 
} 

Jetzt müssen wir uns die dismissBlock nur sicherstellen, haben als eine Eigenschaft definiert in ViewControllerC.h (Sie können natürlich diesen ganzen Teil Methoden mit Delegierten ersetzen oder andere, ebenso wie spannendem Design-Muster, ist der wichtige Teil Entlassung am viewControllerB Ebene zu behandeln)

// ViewControllerC.h 
@interface ViewControllerC : UIViewController 
@property (nonatomic, copy) void (^dismissBlock)(void); 
@end 

//ViewControllerC.m 
// Make an method to handle dismissal that is called by button press or whatever logic makes sense. 
- (void)closeButtonPressed { 
    if (_dismissBlock) {// If the dismissblock property was set, let the block handle dismissing 
     _dismissBlock(); 
     return; 
    } 

    // Leaving this here simply allows the viewController to be presented modally as the base as well or allow the presenter to handle it with a block. 
    [self dismissViewControllerAnimated:YES completion:nil]; 
} 

hoffte, das hilft, glücklich Programmierung :)

+0

upvote für eine funktionierende Lösung, aber das ist einfach verrückt (im Vergleich zu seinem Vorteil) –

+1

Es ist, aber es gibt buchstäblich keine gute funktionierende Lösung, die einfach ist und gut aussieht. Ich war frustriert, dass Apple nicht schon einen guten Weg hatte, damit umzugehen. Hoffentlich mit der neuen Version in diesem Herbst. – johnrechd

+0

Absolut zutreffend. Ich bin einen anderen Weg gegangen und habe die viewControllers nacheinander abgewiesen (es ist keine Lösung für das Problem, aber es funktioniert und ist nicht _that_ hässlich) –