Хотя принятый ответ сработал для меня, он может устареть и оставить странную анимацию, где самый верхний модал немедленно исчезнет, и анимация будет на заднем модальном виде.Я перепробовал много вещей, чтобы избежать этого, и в итоге мне пришлось использовать немного хака, чтобы он выглядел красиво.Примечание: (протестировано только в iOS8 +, но должно работать в iOS7 +)
По сути, viewControllerA создает UINavigationController
с viewControllerB
в качестве корневого представления и представляет его модально.
// 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];
}
Теперь вviewControllerB
мы собираемся представить viewControllerC
таким же образом, но после того, как мы представим его, мы собираемся поместить снимок viewControllerC
поверх слоя представления на контроллере навигации viewControllerB
.Затем, когда viewControllerC
исчезнет во время увольнения, мы не увидим изменения и анимация будет выглядеть красиво.
//ViewControllerB.m
- (void)presentViewC {
ViewControllerC *viewControllerC = [[ViewControllerC alloc] init];
// Custom presenter method to handle setting up dismiss and snapshotting
// I use this in a menu that can present many VC's so I centralized this part.
[self presentViewControllerForModalDismissal:viewControllerC];
}
Ниже приведены мои вспомогательные функции, которые используются для представления вида и обработки увольнения.Стоит отметить, что я использую Purelayout для добавления ограничений автоматического макета.Вы можете изменить это, чтобы добавить их вручную или получить Purelayout в 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;
}
Теперь нам просто нужно убедиться, что dismissBlock определен как свойство в ViewControllerC.h (очевидно, вы можете заменить всю эту частьпри использовании методов делегата или других столь же интересных шаблонов проектирования важной частью является обработка увольнения на уровне viewControllerB)
// 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];
}
Надеюсь, это поможет, счастливое программирование:)