如何添加在Objective-C中有自己的UIViewController的子视图?

我正在努力与自己的UIViewControllers子视图。 我有一个UIViewController视图(淡粉色)和两个button在toolbar 。 我想要在第一个button被按下时显示蓝色视图,而按下第二个button时要显示黄色视图。 如果我只想显示一个视图,应该很容易。 但蓝色视图将包含一个表,所以它需要它自己的控制器。 那是我的第一课。 我从这个问题开始,在那里我学到了我需要一个控制器的表。

所以,我要回来,在这里采取一些婴儿的步骤。 下面是我的Utility ViewController (主视图控制器)和另外两个控制器(蓝色和黄色)的一个简单起点的图片。 想象一下,当首次显示Utility ViewController (主视图)时,蓝色(默认)视图将显示在粉色视图所在的位置。 用户将能够点击两个button来回,粉红色的视图将永远不会显示。 我只想让蓝色的视图去粉红色的视图,黄色的视图去粉红色的视图。 我希望这是有道理的。

简单的故事板图像

我试图使用addChildViewController 。 从我所看到的,有两种方式来做到这一点:在storyboard的容器视图或编程addChildViewController 。 我想以编程方式做到这一点。 我不想使用NavigationController或选项卡栏。 我只是想添加控制器,并按下相关联的button时正确的视图到粉红色的视图。

以下是我到目前为止的代码。 我想要做的就是显示粉红色视图所在的蓝色视图。 从我所看到的,我应该能够addChildViewController和addSubView。 这个代码不是为我做的。 我的困惑越来越好。 有人可以帮我把粉红色的视图显示在蓝色的视图?

除了在viewDidLoad中显示蓝色视图之外,此代码无意做任何其他操作。

IDUtilityViewController.h

 #import <UIKit/UIKit.h> @interface IDUtilityViewController : UIViewController @property (strong, nonatomic) IBOutlet UIView *utilityView; @end 

IDUtilityViewController.m

 #import "IDUtilityViewController.h" #import "IDAboutViewController.h" @interface IDUtilityViewController () @property (nonatomic, strong) IDAboutViewController *aboutVC; @end @implementation IDUtilityViewController - (void)viewDidLoad { [super viewDidLoad]; self.aboutVC = [[IDAboutViewController alloc]initWithNibName:@"AboutVC" bundle:nil]; [self addChildViewController:self.aboutVC]; [self.aboutVC didMoveToParentViewController:self]; [self.utilityView addSubview:self.aboutVC.aboutView]; } @end 

– – – – – – – – – – – – – 编辑 – – – – – – – – – – – – ——-

self.aboutVC.aboutView是零。 但是我把它连接在storyboard 。 我还需要实例化吗?

在这里输入图像描述

这篇文章总是有最新的Swift语法,比如Swift 3/4。

在今天的iOS中, “一切都是容器视图” 。 这是您今天制作应用的基本方式。

一个应用程序可能很简单,它只有一个视图。 但即使在这种情况下,屏幕上的每个“东西”都是一个容器视图。

这是简单的…


(A)将一个容器视图拖到你的场景中…

将容器视图拖到场景视图中。 (就像你会拖入一个UIButton一样。)

容器视图是这个图像中的棕色的东西。 它实际上是你的场景视图中。

在这里输入图像描述

将容器视图拖到场景视图中时,Xcode会自动给你两件事

  1. 您可以在场景视图中获取容器视图,

  2. 你得到一个全新的UIViewController ,它只是坐在你的故事板的白色的某个地方

这两个与“共济会的象征”的东西 – 下面解释!


(B)点击那个新的视图控制器(Xcode为你在白色区域的某个地方制作的新东西, 而不是你场景中的东西 )…并且改变这个类!

这真的很简单。

你完成了。


这是解释视觉相同的事情。

(A)注意容器视图

(B)注意到控制器

显示一个容器视图和相关的视图控制器

点击B.(这是B – 不是A!)

去右上angular的检查员。 注意它说“UIViewController”

[ 在这里输入图像描述 ] [3]

将其更改为您自己的自定义类,这是一个UIViewController。

在这里输入图像描述

所以,我有一个Swift类Snap是一个UIViewController

在这里输入图像描述

所以我在Inspector中的“UIViewController”中input“Snap”。

(像往常一样,当你开始input“Snap …”时,Xcode会自动完成“Snap”)。

这就是这一切 – 你完成了。


如何更改容器视图 – 比如,表格视图。

所以当你点击添加一个容器视图时,苹果会自动给你一个链接的视图控制器,坐在故事板上。

正如(2017)所示:默认情况下,它使它成为一个UIViewController

这很愚蠢:它应该问你需要哪种types。 例如,你经常需要一个表格视图。 以下是如何将其更改为不同的方式:

在写这篇文章时,Xcode默认给你一个UIViewController 。 假设你想要一个UICollectionViewController来代替:

(i)将一个容器视图拖到你的场景中。 看一下Xcode默认给你的故事板上的UIViewController。

(ii)将新的UICollectionViewController拖动到故事UICollectionViewController白色区域的任何位置。

(iii)点击场景中的容器视图。 点击连接检查器。 注意有一个“触发的Segue”。 将鼠标hover在“触发的Segue”上,并注意到Xcode 突出显示了所有不需要的UIViewController。

(iv)点击“x”实际删除触发的塞恩。

(v) 触发的Segue中拖动 (viewDidLoad是唯一的select)。 将故事板拖到新的UICollectionViewController。 出现一个popup窗口。 您必须selectembedded

(vi)简单地删除所有不需要的UIViewController。 你完成了。

短版本:删除不需要的UIViewController。 在故事板上放置一个新的UICollectionViewController 。 控制 – 从容器视图的连接 – 触发Segue – viewDidLoad拖动到您的新控制器。 一定要select“embedded”popup。


input文本标识符…

你将有一个“正方形”的共鸣符号事物:它在连接你的容器视图和视图控制器的“弯曲线”上。

“共济会的标志”的东西是赛格。

在这里输入图像描述

点击“共济会的符号”的东西select赛格。

看你的权利。

必须input一个文字标识符

你决定这个名字。 它可以是任何文本string。 明智的select通常是“segueClassName”。

如果你遵循这个模式,你所有的segues将被称为segueClockView,seguePersonSelector,segueSnap,segueCards等等。

接下来,你在哪里使用该文本标识符?


如何连接'到'子控制器…

然后,在代码中,在整个场景的ViewController中执行以下操作。

假设在场景中有三个容器视图。 每个容器视图都有一个不同的控制器,比如“Snap”,“Clock”和“Other”。

最新的Swift3语法(2017)

 var snap:Snap? var clock:Clock? var other:Other? override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if (segue.identifier == "segueSnap") { snap = (segue.destination as! Snap) } if (segue.identifier == "segueClock") { clock = (segue.destination as! Clock) } if (segue.identifier == "segueOther") { other = (segue.destination as! Other) } } 

就这么简单。 您可以使用prepareForSegue调用连接一个variables来引用控制器。


如何在“其他方向”连接,直至父母…

假设你已经在容器视图中放置了控制器(在示例中为“Snap”)。

到达上方的“boss”视图控制器(例如“Dash”)可能会造成混淆。 幸运的是,这很简单:

 // Dash is the overall scene. // Here we are in Snap. Snap is one of the container views inside Dash. class Snap { var myBoss:Dash? override func viewDidAppear(_ animated: Bool) { // MUST be viewDidAppear super.viewDidAppear(animated) myBoss = self.parent as? Dash } 

关键:只能从viewDidAppear或更高版本才能使用。 将无法在viewDidLoad工作。

你完成了。


重要说明: 适用于容器视图。

重要的高级技巧:不要忘记,只适用于容器视图。

如今,有了故事板标识符,在屏幕上popup新视图(而不是在Android开发中)是司空见惯的事情。 所以,假设用户想要编辑一些东西…

  // let's just pop a view on the screen. // this has nothing to do with container views // let e = ...instantiateViewController(withIdentifier: "Edit") as! Edit e.modalPresentationStyle = .overCurrentContext self.present(e, animated: false, completion: nil) 

当使用容器视图时, 保证 Dash将是Snap的父视图控制器。

但是,当你使用instantiateViewController时,这不是必须的。

非常容易混淆,在iOS中,父视图控制器实例化它的类没有关系 。 (它可能是一样的,但通常不一样。) self.parent模式适用于容器视图。

(对于instantiateViewController模式中的类似结果,您必须使用协议和委托,记住委托将是一个薄弱环节。)


prepareForSegue命名不佳…

值得注意的是,“准备好塞子”是一个非常糟糕的名字!

“prepareForSegue”用于两个目的:加载容器视图,以及在场景之间循环。

但在实践中,你很less在场景之间漫游! 几乎每个应用程序都有许多容器视图。

如果“prepareForSegue”被称为“loadingContainerView”,那将会更有意义。


超过一个…

一个常见的情况是:屏幕上有一个小区域,您想在其中显示多个不同的视图控制器中的一个。 例如,四个小部件之一。

最简单的方法:只有四个不同的容器视图都坐在同一个区域 。 在你的代码中,只需隐藏所有四个,打开你想看到的那个。

在故事板上,有一个空的“持有人”UIView,它只保存四个容器视图。 然后,您可以通过调整或移动“持有人”来一次调整或移动所有四个。 在你的代码中,只需要有四个UIViewsockets,每个容器视图一个。 复制并粘贴上面的代码,“如何连接到子控制器”,连接四个包含的视图控制器。


注 – 故事板参考到达!

正如SimplGy在“iOS 9的Storyboard References ”中指出的那样, 容器视图更加可怕,您可以在任何地方定义可重用的视图(控制器),并从多个模块化故事板中的任何容器视图中引用它。

还要注意,相当容易混淆 – 通常今天你只是不打扰容器视图!

在许多情况下,您只需instantiateViewController#withIdentifier

但是请注意上面解释的关于.parent的“gotchya”。 容器视图的全部要点就是你可以立即简单地确定父链。

如果你用instantiateViewController#withIdentifier使用storyboard引用,你必须搞乱一个协议和一个委托(记住委托将是一个薄弱的环节)。 但是,你可以随时随地灵活地使用它。

相比之下,使用“固定”,可以说,容器视图是非常简单的,你可以立即在父母和孩子之间挂钩,如上所述。

我看到两个问题。 首先,因为你正在制作故事板中的控制器,所以你应该使用instantiateViewControllerWithIdentifier来实例化它们,而不是initWithNibName:bundle: 其次,将视图添加为子视图时,应该给它一个框架。 所以,

 - (void)viewDidLoad { [super viewDidLoad]; self.aboutVC = [self.storyboard instantiateViewControllerWithIdentifier:@"aboutVC"]; // make sure you give the controller this same identifier in the storyboard [self addChildViewController:self.aboutVC]; [self.aboutVC didMoveToParentViewController:self]; self.aboutVC.view.frame = self.utilityView.bounds; [self.utilityView addSubview:self.aboutVC.aboutView]; }