したがって、A がルート、B が最初のモーダル ビュー コントローラー、C が 3 番目のモーダル VC である 3 つのビュー コントローラーを含むスタックがあります。CからAに一気に行きたいです。この解決策を試してみましたが、うまくいきませんが、正しい方法ではありません。つまり、最後のView Controllerが閉じられると、最初のView Controllerが表示される前に、2番目のView Controllerが簡単に表示されます。私が探しているのは、2 番目のビューに気付かずに、1 つの素敵なアニメーションで 3 番目の VC から最初の VC に移動する方法です。これに関するヘルプは非常に高く評価されています。
7 に答える
dismissModalViewControllerAnimated:
呼び出しは 1 回だけにしてください。
スタックされた各モーダル ビュー コントローラーを閉じるように要求すると、両方がアニメーション化されることがわかりました。
あなたが持っている:A =modal> B =modal> C
電話するだけでいい[myViewControllerA dismissModalViewControllerAnimated:YES]
を使用する[myViewControllerB dismissModalViewControllerAnimated:YES]
と、B ではなく C が却下されます。通常の (スタックされていない) 使用では、B が却下されます (レスポンダ チェーンがメッセージを A までバブリングするため)。あなたが説明する積み重ねられたシナリオでは、Bは親ビューコントローラーであり、これはモーダルビューコントローラーよりも優先されます。
受け入れられた答えは私にとってはうまくいきましたが、今では古くなっている可能性があり、一番上のモーダルがすぐに消えてアニメーションが背面のモーダルビューに表示される奇妙なアニメーションが残っています。私はこれを避けるために多くのことを試みましたが、見栄えを良くするためにちょっとしたハックを使わなければならなくなりました。注:(iOS8 以降でのみテストされていますが、iOS7 以降で動作するはずです)
基本的に、viewControllerA は rootview として with を作成し、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];
}
以下は、ビューを表示し、却下を処理するために使用されるヘルパー関数です。注意すべきことの 1 つは、自動レイアウト制約を追加するために Purelayout を使用していることです。これを変更して手動で追加するか、 https: //github.com/PureLayout/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];
}
これが役立つことを願って、幸せなプログラミング:)
rootViewController でこれらの modalViewControllers を閉じることができます。
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];
}
使いたいのは
popToRootViewControllerAnimated:
. 介在するものをすべて表示せずに、ルートコントローラーに移動します。