私のUISplitViewController
では、マスタービューはUINavigationController
を含むUITableViewController
です。時々、ユーザーがテーブル内のアイテムを選択すると、マスタービューの既存のテーブルの上に別のUITableViewController
をプッシュする必要があります。
IOS 7では、最初のUITableViewController
内で
[self.navigationController pushViewController:otherTableVC animated:YES];
IOS 8の場合:
分割ビューを折りたたむと、otherTableVCが詳細ビューになります。次に、デバイスを回転させた後、2つのテーブルが並んで表示されます...
さらに悪いことに、デバイスに2つのペインが表示されている場合、コードは正常に機能し、2番目のテーブルがマスタービューの最初のテーブルの上にプッシュされます。しかし、2回転した後、2つのテーブルは再び並んでいます。 UISplitViewController
の折りたたまれたモードが自分のナビゲーションコントローラーに干渉しているようです…
マスタービューで自分のUINavigationController
を管理するにはどうすればよいですか?
ありがとうございました
編集済み:
プライマリビューと詳細ビューの両方にナビゲーションコントローラーがあります。そして、私の問題を解決するために、折りたたまれたモードで、追加のナビゲーションコントローラーを作成し、それをプライマリナビゲーションコントローラーにプッシュする必要があることを発見しました。
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:otherTableVC];
[self.navigationController pushViewController:navController animated:YES];
だから私は、ナビゲーションコントローラーを別のナビゲーションコントローラー内にプッシュできることを発見しました。
簡単に言うと、UISplitViewControllerDelegateメソッドを使用してこの動作を制御できます。
splitViewController:collapseSecondaryViewController:ontoPrimaryViewController:
splitViewController:separateSecondaryViewControllerFromPrimaryViewController:
あなたが本当にやりたいことは、iOS 8 UISplitViewControllerベースのアプリがあり、プライマリビューと詳細ビューの両方がUINavigationControllersであり、(これらのナビゲーションコントローラー内に)表示したいviewControllersがいくつかある状況に対処することだと思います分割ビューのプライマリ側または詳細側。以下の答えはこれを扱っています。また、詳細ナビゲーションコントローラのビューをプッシュするのではなく、ビューを置き換えたい場合もあります。
小さな注意点:以下のコードは、考えられるすべてのケースを扱っているわけではなく、いくつかの仮定があります。
SplitViewController:collapseSecondaryViewController:ontoPrimaryViewController:/ splitViewController:separateSecondaryViewControllerFromPrimaryViewController:ロジックの片側だけを実装し、もう一方の側のデフォルトの実装に応じて実装することはお勧めしません。 Apple UINavigationViewControllerを詳細側からプライマリナビゲーションコントローラースタックのviewControllerの1つとしてプライマリ側に配置し、他のビューコントローラーをその上にプッシュするなどの奇妙なことを行います。完全に理解しても、自分のコードから複製することはできません。したがって、プロセスの両側を自分で処理するのが最善です。
これは私が使用するものです:
#pragma mark -
#pragma mark Split View Controller delegate.
- (BOOL)splitViewController:(UISplitViewController *)splitViewController showViewController:(UIViewController *)vc sender:(id)sender
{
//Standard behaviour. This won't get called in our case when the split view is collapsed and the primary view controllers are obscured.
return NO;
}
// Since we treat warnings as errors, silence warning about unknown selector below on UIViewController subclasses.
#pragma GCC diagnostic ignored "-Wundeclared-selector"
- (BOOL)splitViewController:(UISplitViewController *)splitViewController showDetailViewController:(UIViewController *)vc sender:(id)sender
{
if (splitViewController.collapsed == NO)
{
// The navigation controller we'll be adding the view controller vc to.
UINavigationController *navController = splitViewController.viewControllers[1];
UIViewController *topDetailViewController = [navController.viewControllers lastObject];
if ([topDetailViewController isKindOfClass:[BlankViewController class]] ||
([vc respondsToSelector:@selector(shouldReplaceDetailedView)] && [vc performSelector:@selector(shouldReplaceDetailedView)]))
{
// Replace the (expanded) detail view with this new view controller.
[navController setViewControllers:@[vc] animated:NO];
}
else
{
// Otherwise, just Push.
[navController pushViewController:vc animated:YES];
}
}
else
{
// Collapsed. Just Push onto the conbined primary and detailed navigation controller.
UINavigationController *navController = splitViewController.viewControllers[0];
[navController pushViewController:vc animated:YES];
}
// We've handled this ourselves.
return YES;
}
- (BOOL)splitViewController:(UISplitViewController *)splitViewController collapseSecondaryViewController:(UIViewController *)secondaryViewController ontoPrimaryViewController:(UIViewController *)primaryViewController
{
UINavigationController *primaryNavController = (UINavigationController *)primaryViewController;
UINavigationController *secondaryNavController = (UINavigationController *)secondaryViewController;
UIViewController *bottomSecondaryView = [secondaryNavController.viewControllers firstObject];
if ([bottomSecondaryView isKindOfClass:[BlankViewController class]])
{
NSAssert([secondaryNavController.viewControllers count] == 1, @"BlankViewController is not only detail view controller");
// If our secondary controller is blank, do the collapse ourself by doing nothing.
return YES;
}
// We need to shift these view controllers ourselves.
// This should be the primary views and then the detailed views on top.
// Otherwise the UISplitViewController does wacky things like embedding a UINavigationController inside another UINavigation Controller, which causes problems for us later.
NSMutableArray *newPrimaryViewControllers = [NSMutableArray arrayWithArray:primaryNavController.viewControllers];
[newPrimaryViewControllers addObjectsFromArray:secondaryNavController.viewControllers];
primaryNavController.viewControllers = newPrimaryViewControllers;
return YES;
}
- (UIViewController *)splitViewController:(UISplitViewController *)splitViewController separateSecondaryViewControllerFromPrimaryViewController:(UIViewController *)primaryViewController
{
UINavigationController *primaryNavController = (UINavigationController *)primaryViewController;
// Split up the combined primary and detail navigation controller in their component primary and detail view controller lists, but with same ordering.
NSMutableArray *newPrimaryViewControllers = [NSMutableArray array];
NSMutableArray *newDetailViewControllers = [NSMutableArray array];
for (UIViewController *controller in primaryNavController.viewControllers)
{
if ([controller respondsToSelector:@selector(shouldDisplayInDetailedView)] && [controller performSelector:@selector(shouldDisplayInDetailedView)])
{
[newDetailViewControllers addObject:controller];
}
else
{
[newPrimaryViewControllers addObject:controller];
}
}
if (newDetailViewControllers.count == 0)
{
// If there's no detailed views on the top of the navigation stack, return a blank view (in navigation controller) for detailed side.
UINavigationController *blankDetailNavController = [[UINavigationController alloc] initWithRootViewController:[[BlankViewController alloc] init]];
return blankDetailNavController;
}
// Set the new primary views.
primaryNavController.viewControllers = newPrimaryViewControllers;
// Return the new detail navigation controller and views.
UINavigationController *detailNavController = [[UINavigationController alloc] init];
detailNavController.viewControllers = newDetailViewControllers;
return detailNavController;
}
私のコードで動作するようにマイナーな変更を加えたSwift4バージョン:
func splitViewController(_ splitViewController: UISplitViewController, showDetail vc: UIViewController, sender: Any?) -> Bool {
if !isCollapsed {
// in expanded mode set new VC as top view controller of the detail nav controller
if let detailNavigationController = viewControllers[1] as? UINavigationController {
detailNavigationController.setViewControllers([vc], animated: false)
}
} else {
// in collapsed mode Push the new view controller on the master nav controller
if let masterNavigationController = viewControllers[0] as? UINavigationController {
masterNavigationController.pushViewController(vc, animated: true)
}
}
return true
}
func splitViewController(_ splitViewController: UISplitViewController, collapseSecondary secondaryViewController: UIViewController, onto primaryViewController: UIViewController) -> Bool {
let masterNavigationController = primaryViewController as? UINavigationController
let detailNavigationController = secondaryViewController as? UINavigationController
let episodeDetailViewController = detailNavigationController?.viewControllers.first as? EpisodeDetailTableViewController
if episodeDetailViewController?.episode == nil {
// detail view is blank. We do not need to Push this onto the master
return true
}
guard var newMasterViewControllers = masterNavigationController?.viewControllers else { return false }
newMasterViewControllers.append(contentsOf: detailNavigationController?.viewControllers ?? [])
masterNavigationController?.setViewControllers(newMasterViewControllers, animated: false)
return true
}
func splitViewController(_ splitViewController: UISplitViewController, separateSecondaryFrom primaryViewController: UIViewController) -> UIViewController? {
let masterNavigationViewController = primaryViewController as? UINavigationController
var newMasterViewControllers = [UIViewController]()
var newDetailViewControllers = [UIViewController]()
for vc in masterNavigationViewController?.viewControllers ?? [] {
if vc is PodcastsTableViewController || vc is EpisodesTableViewController {
newMasterViewControllers.append(vc)
} else {
newDetailViewControllers.append(vc)
}
}
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let detailNavigationController = storyboard.instantiateViewController(withIdentifier: "splitViewDetailViewController") as! UINavigationController
if newDetailViewControllers.count == 0 {
let emptyEpisodeDetailViewController = storyboard.instantiateViewController(withIdentifier: "episodeDetail")
newDetailViewControllers.append(emptyEpisodeDetailViewController)
}
masterNavigationViewController?.setViewControllers(newMasterViewControllers, animated: false)
detailNavigationController.setViewControllers(newDetailViewControllers, animated: false)
return detailNavigationController
}