如何添加在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会自动给你两件事 :
-
您可以在场景视图中获取容器视图,
-
你得到一个全新的
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,它只保存四个容器视图。 然后,您可以通过调整或移动“持有人”来一次调整或移动所有四个。 在你的代码中,只需要有四个UIView
sockets,每个容器视图一个。 复制并粘贴上面的代码,“如何连接到子控制器”,连接四个包含的视图控制器。
注 – 故事板参考到达!
正如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]; }