【发布时间】:2014-08-18 08:30:38
【问题描述】:
iOS - 拆分视图控制器 - 如何从主视图控制器(较小的左侧)内部获取指向详细视图控制器(较大的右侧)的指针(引用)?
我的直觉告诉我主拆分视图控制器应该有对详细视图控制器和我自己的主视图控制器的引用,但我不知道如何获取它。
有什么想法吗?
【问题讨论】:
iOS - 拆分视图控制器 - 如何从主视图控制器(较小的左侧)内部获取指向详细视图控制器(较大的右侧)的指针(引用)?
我的直觉告诉我主拆分视图控制器应该有对详细视图控制器和我自己的主视图控制器的引用,但我不知道如何获取它。
有什么想法吗?
【问题讨论】:
拆分视图控制器确实通过viewControllers 属性引用了它们的主视图控制器和详细视图控制器。
在 iOS 7.x 及更低版本中,viewControllers 数组中应该正好有两个视图控制器对象。第一个对象是主视图控制器,第二个对象是详细视图控制器。
在 iOS 8.0 及更高版本中,viewControllers 数组中至少有一个视图控制器对象——主(或“主”)视图控制器。如果第二个视图控制器对象在数组中,那么它就是细节(或“次要”)视图控制器。拆分视图控制器折叠时,只有主视图控制器在此数组中,展开时它将包含主视图控制器和详细视图控制器。
您可以使用所有视图控制器的splitViewController 属性来获取拆分视图控制器,然后使用viewControllers 属性访问您的主视图控制器或详细视图控制器,如下所示:
斯威夫特:
let masterVC = self.splitViewController?.viewControllers.first
let detailVC = (self.splitViewController?.viewControllers.count > 1) ? self.splitViewController?.viewControllers[1] : nil
目标-C:
UIViewController *masterVC = [self.splitViewController.viewControllers firstObject];
UIViewController *detailVC;
if (self.splitViewController.viewControllers.count > 1) {
detailVC = self.splitViewController.viewControllers[1];
}
splitViewController 属性通过遍历视图控制器层次结构并尝试找到调用视图控制器所在的任何拆分视图控制器来工作。如果视图控制器不在拆分视图控制器中,则该属性为 @987654329 @。它与 navigationController 和 tabBarController 视图控制器属性的工作方式相同。
您可以使用UISplitViewController 上的 Swift 扩展(或 Objective-C 中的类别)使主视图控制器和详细视图控制器更易于访问,就像这样(如果使用您自己的前缀替换所有 xx_你使用的是 Objective-C):
斯威夫特:
extension UISplitViewController {
var primaryViewController: UIViewController? {
return self.viewControllers.first
}
var secondaryViewController: UIViewController? {
return self.viewControllers.count > 1 ? self.viewControllers[1] : nil
}
}
目标-C:
// UISplitViewController+ChildViewControllerAccess.h
@interface UISplitViewController (ChildViewControllerAccess)
@property (nonatomic, readonly) UIViewController *xx_primaryViewController;
@property (nonatomic, readonly) UIViewController *xx_secondaryViewController;
@end
// UISplitViewController+ChildViewControllerAccess.m
@implementation UISplitViewController (ChildViewControllerAccess)
- (UIViewController *)xx_primaryViewController
{
return self.viewControllers.firstObject;
}
- (UIViewController *)xx_secondaryViewController
{
return self.viewControllers.count > 1 ? self.viewControllers[1] : nil;
}
@end
然后您可以像这样使用这些属性:
斯威夫特:
func someFunctionInSomeViewControllerClass {
// Get the primary and secondary view controllers if
// this view controller is in a split view controller.
// These will be nil if this view controller is not a
// descendant of a split view controller.
var primaryVC = self.splitViewController?.primaryViewController
var secondaryVC = self.splitViewController?.secondaryViewController
// Do something with them
primaryVC?.title = "This is the primary VC"
secondaryVC?.title = "This is the secondary VC"
}
目标-C:
#import "UISplitViewController+ChildViewControllerAccess.h"
[...]
- (void)someMethodInSomeViewControllerClass
{
// Get the primary and secondary view controllers if
// this view controller is in a split view controller.
// These will be nil if this view controller is not a
// descendant of a split view controller.
UIViewController *primaryVC = self.splitViewController.xx_primaryViewController;
UIViewController *secondaryVC = self.splitViewController.xx_secondaryViewController;
// Do something with them
primaryVC.title = @"This is the primary VC";
secondaryVC.title = @"This is the secondary VC";
}
【讨论】:
viewControllers属性可能只包含一个视图控制器,“..分屏界面展开时,该属性包含两个视图控制器;当它是折叠后,此属性仅包含一个视图控制器。数组中的第一个视图控制器始终是主(或主)视图控制器。如果存在第二个视图控制器,则该视图控制器是辅助(或细节)视图控制器...”
viewControllers 数组在 iOS 8 中的工作方式。我还为类别添加了一些代码,以使访问这些视图控制器(有点)更容易。
primaryVC 将是一个UINavigationController。好吧,UINavigationController 继承自 UIViewController。要获得您可能想要的视图控制器,请将 primaryVC 向下转换为 UINavigationController 并获得其 topViewController。
如果您使用的是iOS 14+,您可以使用viewController(for:) 方法从splitViewController 获取特定的viewController:
let detailViewController = splitViewController.viewController(for: .secondary) as? DetailViewController
【讨论】:
在你的 UISplitViewController 子类中创建一个属性:
var _detailViewController: UIViewController? {
get {
if viewControllers.count > 1 {
return viewControllers[1] as? UIViewController
}
return nil
}
}
根据 Apple 的文档,这有时应该返回 nil,但根据我的经验,它总是返回详细视图控制器,无论状态如何。
另外,不要将此属性称为“detailViewController”而不是“_detailViewController” - Apple 显然已经在后台使用该名称,它会弄乱您的 UI。
UISplitViewController 真的很老套,需要大量的清理和更正的文档...
【讨论】: