虽然接受的答案确实对我有用,但它现在可能已经过时并且留下了一个看起来很奇怪的动画,其中最上面的模态会立即消失并且动画将在后模态视图上。我尝试了很多方法来避免这种情况,最终不得不使用一些技巧让它看起来不错。
注意:(只在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,但在呈现之后,我们将在viewControllerB 的导航控制器上的视图层上放置viewControllerC 的快照。然后,当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;
}
现在我们只需要确保在 ViewControllerC.h 中定义了dismissBlock 属性(您显然可以将整个部分替换为委托方法或其他同样令人兴奋的设计模式,重要的部分是在 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];
}
希望这会有所帮助,祝你编程愉快:)