0

この質問は長いので、しばらくお待ちください。

ご存知のように、コントローラーを表示するには、プッシュまたは提示の 2 つの方法があります。tabbarcontroller とナビゲーション コントローラーの 2 つの複合コントローラーもあります。これらを使用すると、複雑なビューコントローラー ツリーが作成される可能性があります。今、私はこのような複雑なviewcontrollerツリーを持っています.

T: タブバーコントローラー N: ナビゲーションコントローラー V: 通常のビューコントローラー P: プッシュ S: 存在

したがって、PV2 はビューコントローラーをプッシュすることを意味します。これは 6 つの組み合わせですが、PN は禁止されており、ナビゲーションコントローラーをプッシュすることはできません。そして私が研究しているように

  T1
  ----------------------
  N1 N2 N3
  | | | |
  PV1 PV3
  | |
  PV2

現在のView ControllerはV2です。N3にジャンプしてV3をプッシュしたい。私はこのコードを書きました:

[self.navigationcontroller popToRootViewControllerAnimated:NO]; // No is important
tabbarcontroller.selectIndex = 2;
[N3 pushViewController:V3];

それは機能しますが、それでも悪いです。1: N3 は v3 を認識している必要があります。ViewController 間の結合は強力です。2: 複雑な状況では機能しません...アニメーションの問題も引き起こします。

私の友人は、任意のビューコントローラーを簡単に切り替えることができる PageConductor を作成したと教えてくれました。それは本当に私を混乱させました...

4

1 に答える 1

1
  1. N3 が V3 について知っていることの何が問題になっていますか? V2 が V3 のことを知っているということですか? とにかく、T について知っている V2 にはもっと大きな問題があります。本当にこの複雑な画面フローを実行する必要がある場合は、それを専用オブジェクト (友人が言及した PageConductor など) に委譲します。コントローラー操作 (など[screens showUserProfile:userId]) ではなく、ユーザー アクションの観点からこのオブジェクトに話しかけます。これにより、コントローラー間の実際の分離が実現します。

  2. 「複雑な状況」の例は何ですか? この特定のケースでのアニメーションの問題については、T1 スタックをポップする前に T3 に切り替えてみてください。

アップデート

架空のアプリの画面マネージャーの小さな不自然な例。

@implementation ScreenManager {
}

@synthesize tabController = _tabController;

- (BOOL)goToUserList
{
    // user list is a root controller of tab 0 navigation controller
    BOOL switched = [self switchToTab:0];
    UINavigationController *nc = [self rootNavigationAtTab:0];
    [nc popToRootViewControllerAnimated:!switched]; // we should animate popping if we didn't change tabs
    return switched;
}

- (BOOL)showUserProfile:(NSUInteger)userId
{
    BOOL switched = [self goToUserList];
    UIViewController *uc = [[UserDetailsController alloc] initWithUserId:userId];
    UINavigationController *nc = [self rootNavigationAtTab:0];
    [nc pushViewController:uc animated:YES];
    return switched;
}

- (BOOL)showMapAtLocation:(CLLocation *)location
{
    MapController *mc = [self downcast:[self rootControllerAtTab:1] to:[MapController class]];
    mc.location = location;
    return [self switchToTab:1];
}

/* returns if we actually switched tabs as a result of this action */
- (BOOL)switchToTab:(NSUInteger)tabIdx
{
    NSUInteger prevTabIdx = _tabController.selectedIndex;
    _tabController.selectedIndex = tabIdx;
    return prevTabIdx != tabIdx;
}

- (BOOL)pushController:(UIViewController *)controller animated:(BOOL)animated toTab:(NSUInteger)tabIdx
{
    BOOL switchedTabs = [self switchToTab:tabIdx];
    UINavigationController *nc = [self rootNavigationAtTab:tabIdx];
    [nc pushViewController:controller animated:animated];
    return switchedTabs;
}

- (UINavigationController *)rootNavigationAtTab:(NSUInteger)tabIdx
{
    return [self downcast:[self rootControllerAtTab:tabIdx] to:[UIViewController class]];
}

- (id)downcast:(id)obj to:(Class)klass
{
    return [obj isKindOfClass:klass] ? obj : nil;
}

- (UINavigationController *)rootControllerAtTab:(NSUInteger)tabIdx
{
    return [_tabController.viewControllers objectAtIndex:tabIdx];
}

+ (ScreenManager *)currentManager
{
    static ScreenManager *manager;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
    manager = [ScreenManager new];
});

    return manager;
}


@end

ここでは、「ID ごとにユーザー プロファイルを表示する」、「ユーザー リストを表示する」、「地図上の場所を表示する」という 3 つのアクションをユーザーが利用できます。アプリケーションの要件を満たすためにこの基本的なソリューションを微調整することはできますが、ローカル コントローラー ロジックからタブ/画面管理ロジックを分離するという考えです。すべてのアクションは、タブが切り替えられたかどうかを示すブール値を返すため、クライアント コードはこれに応じて微調整を行うことができます (タブが変更された場合にナビゲーション スタックをポップするなど)。

于 2013-01-20T08:25:05.493 に答える