4

私はサイズ クラスを使用してユニバーサル アプリを実行しており、マスター/プライマリ ビューで TabBarController を使用して SplitView を使用しようとしています。splitView を追加する前はすべて正常に機能していましたが、現在はアプリがクラッシュします (理由はビューの階層によって異なります)。

だから私はApple SplitViewテンプレートから始めて同じストーリーボードを試し、マスター/プライマリビューにTabBarControllerを追加しました...同じ問題。

階層 - TabBarController に埋め込まれたマスター NavigationController: SplitVC (マスター) > TabBarController > NavigationController > TableView SplitVC (詳細) > NavigationController > View

このコードを AppDelegate.m に追加しました (ここで示されているように、 stackoverflow question ios8-tabbarcontroller ... DetailView がモーダルに表示されるのを防ぎます):

- (BOOL)splitViewController:(UISplitViewController *)splitViewController showDetailViewController:(UIViewController *)vc sender:(id)sender {
        NSLog(@"UISplitViewController collapsed: %d", splitViewController.collapsed);

    if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone)
    {
        if (splitViewController.collapsed) {
            UITabBarController *master = (UITabBarController *) splitViewController.viewControllers[0];
            UINavigationController *masterNavigationController = (UINavigationController *)master.selectedViewController;
            UINavigationController *destinationNavigationController = (UINavigationController *)vc;

            // push detail view on the navigation controller
            [masterNavigationController pushViewController:[destinationNavigationController.viewControllers lastObject] animated:YES];

            return YES;
        }
    }

    return NO;
}

正常に動作します... iPhone6 Plusでシミュレートしない限り、その場合、縦向きで開始して行を選択した後、横向きに回転すると、詳細ビ​​ューがプライマリビューとセカンダリビューとして表示されます。

このコードを iPhone で縦向きに追加しないと、詳細ビ​​ューはモーダルで表示され、もちろんナビゲーション ボタンは表示されません。

編集

さまざまな試みの後、いくつかの外部の助けを借りて、解決策に向けていくつかのステップを踏み出しました。

短いバージョン(これを行う必要がある理由については、長いバージョンを参照してください)

この問題の正しい解決策は、TabBarController をサブクラス化し、いくつかのメソッドをサポートすることです。

@implementation MyTabBarController

- (void)showViewController:(UIViewController *)vc sender:(id)sender
{
    if ([self.selectedViewController isKindOfClass:UINavigationController.class])
        [self.selectedViewController showViewController:vc sender:sender];
    else
        [super showViewController:vc sender:sender];
}

- (UIViewController*)separateSecondaryViewControllerForSplitViewController:(UISplitViewController *)splitViewController
{
    return [self.selectedViewController separateSecondaryViewControllerForSplitViewController:splitViewController];
}

- (void)collapseSecondaryViewController:(UIViewController *)secondaryViewController forSplitViewController:(UISplitViewController *)splitViewController
{
    [self.selectedViewController collapseSecondaryViewController:secondaryViewController forSplitViewController:splitViewController];
}

今、viewControllers スタックに問題があります: iPhone6Plus (水平のレギュラーとコンパクトの両方をサポートする唯一のもの) で、横向きのときに行を選択せず​​にタブを変更すると、アプリがクラッシュします (したがって、detailView は前のタブのもののままです) )、縦向きに回転します。

ビュー スタックを適切に管理する分離メソッドと折りたたみメソッドを実装する必要があることはわかっていますが、その方法がわかりません。誰かがこれについて助けることができますか?

長いバージョン(SplitViewController の動作)

通常、分割ビュー コントローラーとナビゲーション コントローラーは連携して動作し、分割ビュー コントローラーに含まれるビュー コントローラーから -showDetailViewController:sender: を呼び出すと、新しい詳細ビュー コントローラーがナビゲーション スタックにプッシュされます (水平にコンパクトな環境)。これを行うために、UISplitViewController は -showDetailViewController:sender: をオーバーライドし、水平方向にコンパクトな場合は、そのマスター ビュー コントローラーの -showViewController:sender: メソッドを呼び出します。UINavigationController は -showViewController:sender: をオーバーライドし、受信ビュー コントローラーをナビゲーション スタックにプッシュします。

ただし、UITabBarController は -showViewController:sender: をオーバーライドしないため、着信ビュー コントローラーをモーダルに表示するデフォルトの実装を継承します。これを回避するには、UITabBarController をサブクラス化し、-showViewController:sender: をオーバーライドして、selectedViewController がナビゲーション コントローラーの場合、タブ バー コントローラーの selectedViewController に転送する必要があります。

さらに、分割ビュー コントローラーがコンパクトから水平サイズのクラスから通常の水平サイズのクラスに移行する場合、分割ビュー コントローラーは最初に -splitViewController:separateSecondaryViewControllerFromPrimaryViewController: メッセージをそのデリゲートに送信します。デリゲートは、このメソッドを実装して分離自体を処理し、詳細ビュー コントローラーを返すことができます。デリゲートがこのメソッドを実装しない場合、または実装が nil を返す場合、分割ビュー コントローラーは -separateSecondaryViewControllerForSplitViewController: メッセージをプライマリ ビュー コントローラーに送信します。プライマリ ビュー コントローラーは、分離を処理するためにこのメソッドを実装する必要があります。UINavigationController は -separateSecondaryViewControllerForSplitViewController: を実装します。これ' s の実装は、トップ ビュー コントローラーをナビゲーション スタックからポップして返します。タブ バー コントローラーをプライマリ ビュー コントローラーとして使用しているため、 -separateSecondaryViewControllerForSplitViewController: を実装し、自分で分離を処理する必要があります。

また、独自の折りたたみロジックを実装する必要があります。分割ビュー コントローラーが通常の水平サイズのクラスからコンパクトな水平サイズのクラスに移行するとき、分割ビュー コントローラーは最初に -splitViewController:collapseSecondaryViewController:ontoPrimaryViewController: メッセージをそのデリゲートに送信します。デリゲートは、このメソッドを実装して、折りたたみ自体を処理できます。デリゲートがこのメソッドを実装していない場合、分割ビュー コントローラーは -collapseSecondaryViewController:forSplitViewController: メッセージをプライマリ ビュー コントローラーに送信します。プライマリ ビュー コントローラーは、分離を処理するためにこのメソッドを実装する必要があります。

UINavigationController は -collapseSecondaryViewController:forSplitViewController: を実装しています。この実装は、セカンダリ ビュー コントローラーをナビゲーション スタックにプッシュします。タブ バー コントローラーをプライマリ ビュー コントローラーとして使用しているため、-collapseSecondaryViewController:forSplitViewController: を実装し、折りたたみを自分で処理する必要があります。

4

2 に答える 2