47

ViewControllerの階層が長いです。

最初のViewControllerでは、次のコードを使用します。

SecondViewController *svc = [[SecondViewController alloc] initWithNibName:@"SecondViewController" bundle:nil];
[self presentModalViewController:svc animated:YES];    
[svc release];

2番目のViewControllerでは、次のコードを使用します。

ThirdViewController *tvc = [[ThirdViewController alloc] initWithNibName:@"ThirdViewController" bundle:nil];
[self presentModalViewController:tvc animated:YES];    
[tvc release];

等々。

そのため、多くのView Controllerがあり、最初のViewControllerに戻る必要がある瞬間があります。一度に1つのステップに戻ると、すべてのViewControllerで次のコードを使用します。

[self dismissModalViewControllerAnimated:YES];

たとえば、6番目のView Controllerから最初のViewControllerに直接戻りたい場合、すべてのControllerを一度に閉じるにはどうすればよいですか?

ありがとう

4

22 に答える 22

67

はい。すでにたくさんの回答がありますが、とにかくリストの最後に 1 つ追加します。問題は、階層のベースにあるビュー コントローラーへの参照を取得する必要があることです。@Juan Munhoes Junior の回答のように、階層をたどることはできますが、ユーザーがたどるルートが異なる可能性があるため、それはかなり脆弱な回答です。この単純なソリューションを拡張することは難しくありませんが、階層をたどってスタックの一番下を探します。一番下の 1 つで reject を呼び出すと、他のすべても取得されます。

-(void)dismissModalStack {
    UIViewController *vc = self.presentingViewController;
    while (vc.presentingViewController) {
        vc = vc.presentingViewController;
    }
    [vc dismissViewControllerAnimated:YES completion:NULL];
}

これはシンプルで柔軟です。スタック内の特定の種類のビュー コントローラーを探したい場合は、に基づいてロジックを追加できます[vc isKindOfClass:[DesiredViewControllerClass class]]

于 2015-01-06T22:06:52.383 に答える
26

解決策を見つけました。

もちろん、最も明白な場所で解決策を見つけることができるので、dismissModalViewControllerAnimated メソッドの UIViewController リファレンスから読んでください...

複数のモーダル ビュー コントローラーを連続して提示し、モーダル ビュー コントローラーのスタックを構築する場合、スタック内の下位にあるビュー コントローラーでこのメソッドを呼び出すと、スタック内の直接の子ビュー コントローラーとその子の上にあるすべてのビュー コントローラーが破棄されます。これが発生すると、最上位のビューのみがアニメーション形式で閉じられます。中間のView Controllerはスタックから単純に削除されます。最上位のビューは、そのモーダル遷移スタイルを使用して閉じられます。これは、スタック内の下位にある他のビュー コントローラーで使用されるスタイルとは異なる場合があります。

そのため、ターゲット ビューで DismissModalViewControllerAnimated を呼び出すだけで十分です。次のコードを使用しました。

[[[[[self parentViewController] parentViewController] parentViewController] parentViewController] dismissModalViewControllerAnimated:YES];

私の家に帰ります。

于 2010-06-02T12:49:55.470 に答える
15

最初のビュー コントローラーがルート/初期ビュー コントローラーでもあるとします (ストーリーボードで初期ビュー コントローラーとして指定したもの)。提示されたすべてのView Controllerを閉じるリクエストをリッスンするように設定できます。

FirstViewController で:

- (void)viewDidLoad {
    [super viewDidLoad];

    // listen to any requests to dismiss all stacked view controllers
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(dismissAllViewControllers:) name:@"YourDismissAllViewControllersIdentifier" object:nil];

    // the remainder of viewDidLoad ...
}

// this method gets called whenever a notification is posted to dismiss all view controllers
- (void)dismissAllViewControllers:(NSNotification *)notification {
    // dismiss all view controllers in the navigation stack
    [self dismissViewControllerAnimated:YES completion:^{}];
}

また、ナビゲーション スタックの他のビュー コントローラーでは、ナビゲーション スタックの一番上に戻る必要があると判断します。

[[NSNotificationCenter defaultCenter] postNotificationName:@"YourDismissAllViewControllersIdentifier" object:self];

これにより、モーダルに表示されたすべてのビュー コントローラーがアニメーションで閉じられ、ルート ビュー コントローラーのみが残ります。これは、最初のビュー コントローラーが UINavigationController であり、最初のビュー コントローラーがルート ビュー コントローラーとして設定されている場合にも機能します。

おまけのヒント: 通知名が同じであることが重要です。入力ミスによる誤解を避けるために、この通知名をアプリのどこかに変数として定義することをお勧めします。

于 2013-08-31T10:41:42.857 に答える
4

スウィフトの場合:

self.presentingViewController?.presentingViewController?.dismissViewControllerAnimated(true, completion: nil)
于 2015-03-26T17:25:24.303 に答える
3

これを試して..

ThirdViewController *tvc = [[ThirdViewController alloc] initWithNibName:@"ThirdViewController" bundle:nil];
[self.view addsubview:tvc];    
[tvc release];
于 2012-11-27T09:05:21.010 に答える
1

単純な再帰クローザー:

extension UIViewController {
    final public func dismissEntireStackAndSelf(animate: Bool = true) {
        // Always false on non-calling controller
        presentedViewController?.ip_dismissEntireStackAndSelf(false)
        self.dismissViewControllerAnimated(animate, completion: nil)
    }
}

これにより、すべての子コントローラーが強制的に閉じられ、自分自身のみがアニメーション化されます。好きなように切り替えることができますが、各コントローラーをアニメーション化すると、コントローラーが 1 つずつ動き、遅くなります。

電話

baseController.dismissEntireStackAndSelf()
于 2016-01-28T00:06:09.397 に答える
1

ルートView Controllerに戻るために、すべてのView Controllerをポップして閉じるために使用するソリューションを次に示します。UIViewController のカテゴリにこれら 2 つのメソッドがあります。

+ (UIViewController*)topmostViewController
{
    UIViewController* vc = [[[UIApplication sharedApplication] keyWindow] rootViewController];
    while(vc.presentedViewController) {
        vc = vc.presentedViewController;
    }
    return vc;
}

+ (void)returnToRootViewController
{
    UIViewController* vc = [UIViewController topmostViewController];
    while (vc) {
        if([vc isKindOfClass:[UINavigationController class]]) {
            [(UINavigationController*)vc popToRootViewControllerAnimated:NO];
        }
        if(vc.presentingViewController) {
            [vc dismissViewControllerAnimated:NO completion:^{}];
        }
        vc = vc.presentingViewController;
    }
}

それから私はちょうど電話します

[UIViewController returnToRootViewController];
于 2014-12-14T11:37:46.537 に答える
1

上記の回答に基づくSwift拡張:

extension UIViewController {

    func dismissUntilAnimated<T: UIViewController>(animated: Bool, viewController: T.Type, completion: ((viewController: T) -> Void)?) {
        var vc = presentingViewController!
        while let new = vc.presentingViewController where !(new is T) {
            vc = new
        }
        vc.dismissViewControllerAnimated(animated, completion: {
            completion?(viewController: vc as! T)
        })
    }
}

スウィフト 3.0 バージョン:

extension UIViewController {

    /// Dismiss all modally presented view controllers until a specified view controller is reached. If no view controller is found, this function will do nothing.

    /// - Parameter reached:      The type of the view controller to dismiss until.
    /// - Parameter flag:         Pass `true` to animate the transition.
    /// - Parameter completion:   The block to execute after the view controller is dismissed. This block contains the instance of the `presentingViewController`. You may specify `nil` for this parameter.
    func dismiss<T: UIViewController>(until reached: T.Type, animated flag: Bool, completion: ((T) -> Void)? = nil) {
        guard let presenting = presentingViewController as? T else {
            return presentingViewController?.dismiss(until: reached, animated: flag, completion: completion) ?? ()
        }

        presenting.dismiss(animated: flag) {
            completion?(presenting)
        }
    }
}

ほとんどの場合、モーダル ビュー コントローラーの表示ビュー コントローラーがUITabBarControllerこれを完全に役に立たなくしていることを考えると、これは信じられないほど愚かなロジックであるため、なぜこれを作成したのかを完全に忘れていました。基本View Controllerインスタンスを実際に取得してそれを呼び出す方がはるかに理にかなってdismissいます。

于 2016-08-05T12:40:34.253 に答える
1
  id vc = [self presentingViewController];
  id lastVC = self;
  while (vc != nil) {
    id tmp = vc;
    vc = [vc presentingViewController];
    lastVC = tmp;
  }
  [lastVC dismissViewControllerAnimated:YES completion:^{
}];
于 2013-09-26T14:45:25.597 に答える
1

まず第一に、あなたのコードに感謝します。

最初に navigationController を開始するには、この方法でもう少し動的にすることができます。(スタック内のViewControllerの数がわからない場合)

NSArray *viewControllers = self.navigationController.viewControllers;
[self.navigationController popToViewController: [viewControllers objectAtIndex:0] animated: YES];
于 2011-02-23T14:35:48.620 に答える
0

アニメーション化された上位の VC を無視し、他のものを非表示にします。モーダル VC が 3 つある場合

[self dismissModalViewControllerAnimated:NO]; // First
[self dismissModalViewControllerAnimated:NO]; // Second
[self dismissModalViewControllerAnimated:YES]; // Third

編集: 1 つのメソッドのみでこれを行う場合は、階層を VC の配列に保存し、アニメーション化された最後のオブジェクトを破棄し、他のオブジェクトは破棄しません。

于 2010-05-31T14:53:45.900 に答える
-1

最初に戻る場合は、コード [self.navigationController popToRootViewControllerAnimated:YES]; を使用できます。

于 2011-10-07T14:41:51.193 に答える