84

UINavigationControllerのスタックから1つのビューを削除し、それを別のビューに置き換える必要があるアプリケーションがあります。状況は、最初のビューが編集可能なアイテムを作成し、次にそれ自体をアイテムのエディターに置き換えることです。私が最初のビュー内で明白な解決策を実行するとき:

MyEditViewController *mevc = [[MYEditViewController alloc] initWithGizmo: gizmo];

[self retain];
[self.navigationController popViewControllerAnimated: NO];
[self.navigationController pushViewController: mevc animated: YES];
[self release];

私は非常に奇妙な行動をします。通常はエディタービューが表示されますが、ナビゲーションバーの[戻る]ボタンを使用しようとすると、余分な画面が表示され、一部が空白になり、一部が台無しになります。タイトルもランダムになります。これは、ナビゲーションスタックが完全にホースで固定されているようなものです。

この問題へのより良いアプローチは何でしょうか?

ありがとう、マット

4

16 に答える 16

137

viewControllersプロパティを手動でいじる必要はまったくないことがわかりました。基本的に、これには 2 つのトリッキーな点があります。

  1. self.navigationControllerが現在ナビゲーション コントローラーのスタックにないnil場合は戻ります。selfしたがって、アクセスできなくなる前にローカル変数に保存してください。
  2. そうしないretainと、現在のメソッドを所有releaseするselfオブジェクトの割り当てが解除され、奇妙なことが発生します。

その準備ができたら、通常どおりポンと押してください。このコードは、すぐにトップ コントローラーを別のコントローラーに置き換えます。

// locally store the navigation controller since
// self.navigationController will be nil once we are popped
UINavigationController *navController = self.navigationController;

// retain ourselves so that the controller will still exist once it's popped off
[[self retain] autorelease];

// Pop this controller and replace with another
[navController popViewControllerAnimated:NO];
[navController pushViewController:someViewController animated:NO];

その最後の行で を に変更するanimatedYES、新しい画面が実際にアニメーション化され、ポップしたばかりのコントローラーがアニメーション化されます。かなりいいですね!

于 2009-11-24T01:59:36.797 に答える
56

次のアプローチは私にはより良いように思え、ARC でもうまく機能します。

UIViewController *newVC = [[UIViewController alloc] init];
// Replace the current view controller
NSMutableArray *viewControllers = [NSMutableArray arrayWithArray:[[self navigationController] viewControllers]];
[viewControllers removeLastObject];
[viewControllers addObject:newVC];
[[self navigationController] setViewControllers:viewControllers animated:YES];
于 2012-01-04T11:11:25.513 に答える
9

経験上、UINavigationController のviewControllersプロパティを直接いじる必要があります。このようなものが動作するはずです:

MyEditViewController *mevc = [[MYEditViewController alloc] initWithGizmo: gizmo];

[[self retain] autorelease];
NSMutableArray *controllers = [[self.navigationController.viewControllers mutableCopy] autorelease];
[controllers removeLastObject];
self.navigationController.viewControllers = controllers;
[self.navigationController pushViewController:mevc animated: YES];

注:保持/解放を保持/自動解放に変更したのは、一般的により堅牢であるためです.保持/解放の間に例外が発生した場合、自己リークしますが、自動解放がそれを処理します.

于 2009-01-04T23:57:09.433 に答える
7

多くの努力 (および Kevin からのコードの微調整) の後、スタックからポップされるビュー コントローラーでこれを行う方法を最終的に見つけました。私が抱えていた問題は、コントローラー配列から最後のオブジェクトを削除した後、self.navigationController が nil を返すことでした。インスタンスメソッドnavigationControllerのUIViewControllerのドキュメントにあるこの行が原因だったと思います「ビューコントローラーがスタックにある場合にのみ、ナビゲーションコントローラーを返します。」

現在のView Controllerがスタックから削除されると、そのnavigationControllerメソッドはnilを返すと思います。

動作する調整されたコードは次のとおりです。

UINavigationController *navController = self.navigationController;
MyEditViewController *mevc = [[MYEditViewController alloc] initWithGizmo: gizmo];

NSMutableArray *controllers = [[self.navigationController.viewControllers mutableCopy] autorelease];
[controllers removeLastObject];
navController.viewControllers = controllers;
[navController pushViewController:mevc animated: YES];
于 2009-01-10T01:10:31.443 に答える
4

ありがとう、これはまさに私が必要としていたものでした。また、これをアニメーションに入れて、ページのカールを取得します。

        MyEditViewController *mevc = [[MYEditViewController alloc] initWithGizmo: gizmo];

    UINavigationController *navController = self.navigationController;      
    [[self retain] autorelease];

    [UIView beginAnimations:nil context:NULL]; [UIView setAnimationDuration: 0.7];
    [UIView setAnimationTransition:<#UIViewAnimationTransitionCurlDown#> forView:navController.view cache:NO];

    [navController popViewControllerAnimated:NO];
    [navController pushViewController:mevc animated:NO];

    [UIView commitAnimations];

0.6 持続時間は高速で、3GS 以降に適しています。0.8 は 3G にはまだ少し速すぎます..

ヨハン

于 2010-06-23T14:50:51.903 に答える
1

これは、viewControllers配列を直接操作する必要のない別のアプローチです。コントローラがまだポップされているかどうかを確認し、ポップされている場合はプッシュします。

TasksViewController *taskViewController = [[TasksViewController alloc] initWithNibName:nil bundle:nil];

if ([navigationController.viewControllers indexOfObject:taskViewController] == NSNotFound)
{
    [navigationController pushViewController:taskViewController animated:animated];
}
else
{
    [navigationController popToViewController:taskViewController animated:animated];
}
于 2012-06-01T14:36:26.643 に答える
1

このUINavigationControllerインスタンスメソッドはうまくいくかもしれません...

指定されたView Controllerが最上位のView ControllerになるまでView Controllerをポップしてから、表示を更新します。

- (NSArray *)popToViewController:(UIViewController *)viewController animated:(BOOL)animated
于 2009-01-04T05:03:16.303 に答える
1

私は最近同様のことをしなければならず、私の解決策はマイケルの答えに基づいていました。私の場合、Navigation Stack から 2 つの View Controller を削除してから、新しい View Controller を追加する必要がありました。通話中

[コントローラ removeLastObject];
2回、私の場合はうまくいきました。

UINavigationController *navController = self.navigationController;

// retain ourselves so that the controller will still exist once it's popped off
[[self retain] autorelease];

searchViewController = [[SearchViewController alloc] init];    
NSMutableArray *controllers = [[self.navigationController.viewControllers mutableCopy] autorelease];

[controllers removeLastObject];
// In my case I want to go up two, then push one..
[controllers removeLastObject];
navController.viewControllers = controllers;

NSLog(@"controllers: %@",controllers);
controllers = nil;

[navController pushViewController:searchViewController animated: NO];

于 2011-03-24T04:06:50.763 に答える
1

私のお気に入りの方法は、UINavigationController のカテゴリを使用することです。以下が機能するはずです。

UINavigationController+Helpers.h #import

@interface UINavigationController (Helpers)

- (UIViewController*) replaceTopViewControllerWithViewController: (UIViewController*) controller;

@end

UINavigationController+Helpers.m
#import "UINavigationController+Helpers.h"

@implementation UINavigationController (Helpers)

- (UIViewController*) replaceTopViewControllerWithViewController: (UIViewController*) controller {
    UIViewController* topController = self.viewControllers.lastObject;
    [[topController retain] autorelease];
    UIViewController* poppedViewController = [self popViewControllerAnimated:NO];
    [self pushViewController:controller animated:NO];
    return poppedViewController;
}

@end

次に、View Controller から、次のようにトップ ビューを新しいビューに置き換えることができます。

[self.navigationController replaceTopViewControllerWithViewController: newController];
于 2013-04-22T20:15:46.197 に答える
1
NSMutableArray *controllers = [self.navigationController.viewControllers mutableCopy];
    for(int i=0;i<controllers.count;i++){
       [controllers removeLastObject];
    }
 self.navigationController.viewControllers = controllers;
于 2012-11-23T07:18:17.220 に答える
0

あるいは、

後になるcategoryのを避けるために使用できますself.navigationControllernilpopViewControllerAnimated

ポップして押すだけで、わかりやすく、アクセスする必要はありませんviewControllers....

// UINavigationController+Helper.h
@interface UINavigationController (Helper)

- (UIViewController*) popThenPushViewController:(UIViewController *)viewController animated:(BOOL)animated;

@end


// UINavigationController+Helper.m
@implementation UINavigationController (Helper)

- (UIViewController*) popThenPushViewController:(UIViewController *)viewController animated:(BOOL)animated
{
    UIViewController *v =[self popViewControllerAnimated:NO];

    [self pushViewController:viewController animated:animated];

    return v;
}
@end

あなたのViewControllerで

// #import "UINavigationController+Helper.h"
// invoke in your code
UIViewController *v= [[MyNewViewController alloc] init];

[self.navigationController popThenPushViewController:v animated:YES];

RELEASE_SAFELY(v);
于 2013-08-20T05:27:15.353 に答える
0

ナビゲーションスタックに追加したすべてのビューコントローラーを提供するナビゲーションビューコントローラー配列で確認できます。その配列を使用することで、特定のビュー コントローラーに戻ることができます。

于 2012-09-25T11:15:49.067 に答える
0

このソリューションを使用して、アニメーションを維持します。

[self.navigationController pushViewController:controller animated:YES];
NSMutableArray *newControllers = [NSMutableArray arrayWithArray:self.navigationController.viewControllers];
[newControllers removeObject:newControllers[newControllers.count - 2]];
[self.navigationController setViewControllers:newControllers];
于 2018-02-27T04:28:00.467 に答える
0

モノタッチ/xamarin IOS の場合:

UISplitViewController クラス内。

UINavigationController mainNav = this._navController; 
//List<UIViewController> controllers = mainNav.ViewControllers.ToList();
mainNav.ViewControllers = new UIViewController[] { }; 
mainNav.PushViewController(detail, true);//to have the animation
于 2013-06-25T22:05:49.683 に答える