Ios iPhone上肖像中的UISplitViewController显示了VC的细节,而不是master
我在Xcode 6中使用通用故事板,目标是iOS 7及以上版本。我已经实现了一个Ios iPhone上肖像中的UISplitViewController显示了VC的细节,而不是master,ios,interface-builder,ios8,uisplitviewcontroller,master-detail,Ios,Interface Builder,Ios8,Uisplitviewcontroller,Master Detail,我在Xcode 6中使用通用故事板,目标是iOS 7及以上版本。我已经实现了一个UISplitViewController,它现在在运行ios8的iPhone上本机支持,Xcode将自动为ios7支持它。它工作得非常好,除了在iPhone上以运行iOS 8的纵向模式启动应用程序时,当我第一次看到主视图控制器时,会显示分割视图的详细视图控制器。我认为这是iOS 8的一个bug,因为当你在iOS 7上运行应用程序时,它会正确地显示主视图控制器。但iOS 8现在是通用的,而且这种情况还在发生。如何设置
UISplitViewController
,它现在在运行ios8的iPhone上本机支持,Xcode将自动为ios7支持它。它工作得非常好,除了在iPhone上以运行iOS 8的纵向模式启动应用程序时,当我第一次看到主视图控制器时,会显示分割视图的详细视图控制器。我认为这是iOS 8的一个bug,因为当你在iOS 7上运行应用程序时,它会正确地显示主视图控制器。但iOS 8现在是通用的,而且这种情况还在发生。如何设置它,以便在拆分视图控制器将要折叠时(屏幕上仅显示一个视图控制器),在显示拆分视图控制器时,显示主视图控制器而不是详细信息
我在Interface Builder中创建了此拆分视图控制器。拆分视图控制器是选项卡栏控制器中的第一个视图控制器。主VCs和详细VCs都是内置表视图控制器的导航控制器。哦,天哪,这让我头疼了好几天,我想不出怎么做。最糟糕的是,用主细节模板创建一个新的Xcode iOS项目效果很好。幸运的是,最后,这个小事实就是我如何找到解决方案的 我发现一些帖子建议解决方案是在
UISplitViewControllerDelegate
上实现新的primaryViewControllerForCollapsingSplitViewController:
方法。我试过了,但没有用。苹果在主细节模板中所做的似乎很有效的是实现新的(深吸一口气说这一切)splitViewController:collapseSecondaryViewController:ontopprimaryviewcontroller:
委托方法(再次在UISplitViewControllerDelegate
)。根据调查,这种方法:
要求学员调整主视图控制器,并将次视图控制器合并到折叠的界面中
确保阅读该方法的讨论部分以了解更具体的细节
苹果处理这一问题的方式是:
- (BOOL)splitViewController:(UISplitViewController *)splitViewController
collapseSecondaryViewController:(UIViewController *)secondaryViewController
ontoPrimaryViewController:(UIViewController *)primaryViewController {
if ([secondaryViewController isKindOfClass:[UINavigationController class]]
&& [[(UINavigationController *)secondaryViewController topViewController] isKindOfClass:[DetailViewController class]]
&& ([(DetailViewController *)[(UINavigationController *)secondaryViewController topViewController] detailItem] == nil)) {
// Return YES to indicate that we have handled the collapse by doing nothing; the secondary controller will be discarded.
return YES;
} else {
return NO;
}
}
此实现基本上执行以下操作:
secondaryViewController
是我们期望的(一个UINavigationController
),并且它显示了我们期望的(一个DetailViewController
--您的视图控制器),但是没有模型(detailItem
),那么“返回YES,表示我们已通过不采取任何行动来处理崩溃;辅助控制器将被丢弃。
“NO
,让拆分视图控制器尝试将次视图控制器的内容合并到折叠的界面中”- 并有一个模型,显示局部视图控制器
- 但没有模型,显示主视图控制器
- 显示主视图控制器
清除为mud。如果没有默认值显示在细节视图控制器中,只需删除故事板中SplitViewController和细节UIViewController之间的默认分段即可。
#import <UIKit/UIKit.h>
@interface SplitProductView : UISplitViewController<UISplitViewControllerDelegate>
@end
这将使它始终首先进入主视图控制器
这样做的副作用是,在启动主视图控制器中的Show Detail Segue之前,您不会在横向视图中看到两个视图,而是在SplitViewController中看到一个全尺寸视图。这是Swift中公认的答案。只需创建此子类,并将其分配给情节提要中的SplitViewController即可
//GlobalSplitViewController.swift
import UIKit
class GlobalSplitViewController: UISplitViewController, UISplitViewControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
self.delegate = self
}
func splitViewController(splitViewController: UISplitViewController, collapseSecondaryViewController secondaryViewController: UIViewController!, ontoPrimaryViewController primaryViewController: UIViewController!) -> Bool{
return true
}
}
马克S正确答案的快速版本
由苹果的主细节模板提供
func splitViewController(splitViewController: UISplitViewController, collapseSecondaryViewController secondaryViewController:UIViewController, ontoPrimaryViewController primaryViewController:UIViewController) -> Bool {
guard let secondaryAsNavController = secondaryViewController as? UINavigationController else { return false }
guard let topAsDetailController = secondaryAsNavController.topViewController as? DetailViewController else { return false }
if topAsDetailController.detailItem == nil {
// Return true to indicate that we have handled the collapse by doing nothing; the secondary controller will be discarded.
return true
}
return false
}
澄清 (马克·S说的有点让人困惑) 此委托方法称为
splitViewController:collapseSecondaryViewController:ontoPrimaryViewController:
,因为它就是这样做的。当更改为更紧凑的宽度大小时(例如,当将手机从横向旋转到纵向时),它只需要将split view控制器折叠为其中一个
此函数返回一个布尔值,以决定是否折叠细节并显示主视图
因此,在我们的例子中,我们将根据是否选择了详细信息来决定。我们如何知道是否选择了我们的详细信息?如果我们遵循Apple的主详细信息模板,详细信息视图控制器应该有一个可选变量,该变量包含详细信息,因此如果它为零(.None),尚未选择任何内容,我们应该显示主控形状,以便用户可以选择一些内容
就这样。在我看来,您应该更通用地解决这个问题。您可以将UISplitViewController子类化,并在嵌入式视图控制器中实现协议
class MasterShowingSplitViewController: UISplitViewController {
override func viewDidLoad() {
super.viewDidLoad()
delegate = self
}
}
extension MasterShowingSplitViewController: UISplitViewControllerDelegate {
func splitViewController(splitViewController: UISplitViewController,
collapseSecondaryViewController secondaryViewController: UIViewController,
ontoPrimaryViewController primaryViewController: UIViewController) -> Bool {
guard let masterNavigationController = primaryViewController as? UINavigationController,
master = masterNavigationController.topViewController as? SplitViewControllerCollapseProtocol else {
return true
}
return master.shouldShowMasterOnCollapse()
}
}
protocol SplitViewControllerCollapseProtocol {
func shouldShowMasterOnCollapse() -> Bool
}
UITableViewController中的示例实现:
extension SettingsTableViewController: SplitViewControllerCollapseProtocol {
func shouldShowMasterOnCollapse() -> Bool {
return tableView.indexPathForSelectedRow == nil
}
}
希望能有帮助。
因此,您可以重用该类,只需实现一个协议。我的应用程序是用Swift 2.x编写的,运行良好。将其转换为Swift 3.0后(使用XCode转换器),它开始在纵向模式下首先显示细节,而不是主控。问题是函数splitViewController的名称没有更改以匹配UISPlitViewController的新名称 手动更改该功能的名称后,我的应用程序现在可以正常工作:
func splitViewController(_ splitViewController: UISplitViewController, collapseSecondary secondaryViewController:UIViewController, onto primaryViewController:UIViewController) -> Bool {
guard let secondaryAsNavController = secondaryViewController as? UINavigationController else { return false }
guard let topAsDetailController = secondaryAsNavController.topViewController as? DetailViewController else { return false }
if topAsDetailController.game == nil {
// Return true to indicate that we have handled the collapse by doing nothing; the secondary controller will be discarded.
return true
}
return false
}
当需要从主控启动时,只需从SplitView控制器中删除DetailViewController
UISplitViewController *splitViewController = (UISplitViewController *)[self.storyboard instantiateViewControllerWithIdentifier:@"SETTINGS"];
splitViewController.delegate = self;
[self.navigationController presentViewController:splitViewController animated:YES completion:nil];
if (IPHONE) {
NSMutableArray * cntlrs = [splitViewController.viewControllers mutableCopy];
[cntlrs removeLastObject];
splitViewController.viewControllers = cntlrs;
}
从中,您需要使用代理通知UISplitViewController
不要将细节视图合并到“折叠界面”(即您的情况下的“纵向模式”)中
UISplitViewController *splitViewController = (UISplitViewController *)[self.storyboard instantiateViewControllerWithIdentifier:@"SETTINGS"];
splitViewController.delegate = self;
[self.navigationController presentViewController:splitViewController animated:YES completion:nil];
if (IPHONE) {
NSMutableArray * cntlrs = [splitViewController.viewControllers mutableCopy];
[cntlrs removeLastObject];
splitViewController.viewControllers = cntlrs;
}
func splitViewController(_ splitViewController: UISplitViewController, collapseSecondary secondaryViewController:UIViewController, onto primaryViewController:UIViewController) -> Bool {
return true
}
class MainSplitViewController: UISplitViewController, UISplitViewControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
self.delegate = self
}
func splitViewController(_ splitViewController: UISplitViewController, collapseSecondary secondaryViewController: UIViewController, onto primaryViewController: UIViewController) -> Bool {
return true
} }
public partial class MainSplitViewController : UISplitViewController
{
public MainSplitViewController(IntPtr handle) : base(handle)
{
}
public override void ViewDidLoad()
{
base.ViewDidLoad();
Delegate = new MainSplitViewControllerDelegate();
}
}
public class MainSplitViewControllerDelegate : UISplitViewControllerDelegate
{
public override bool CollapseSecondViewController(UISplitViewController splitViewController, UIViewController secondaryViewController, UIViewController primaryViewController)
{
return true;
}
}
//Following code in application didFinishLaunching (inside Application Delegate)
guard let splitViewController = window?.rootViewController as? UISplitViewController,
let masterNavVC = splitViewController.viewControllers.first as? UINavigationController,
let masterVC = masterNavVC.topViewController as? MasterViewController
else { fatalError() }
splitViewController.delegate = masterVC
//Following code in MasterViewController class
extension MasterViewController:UISplitViewControllerDelegate {
func splitViewController(_ splitViewController: UISplitViewController, collapseSecondary secondaryViewController: UIViewController, onto primaryViewController: UIViewController) -> Bool {
return true
}
}
import UIKit
class GlobalSplitViewController: UISplitViewController, UISplitViewControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
self.delegate = self
}
func splitViewController(_ splitViewController: UISplitViewController, collapseSecondary secondaryViewController: UIViewController, onto primaryViewController: UIViewController) -> Bool {
return true
}
}
class MySplitViewController: UISplitViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.preferredDisplayMode = .allVisible
}
}