我正在与拥有自己的UIViewControllers
的子视图作斗争。我有一个UIViewController
,带有一个视图(浅粉色)和工具栏上的两个按钮。我希望按下第一个按钮时显示蓝色视图,按下第二个按钮时显示黄色视图。如果我只想显示一个视图,应该很容易。但是蓝色视图将包含一个表,因此它需要自己的控制器。那是我的第一课。我从这个问题开始,在那里我了解到我需要一个桌子的控制器。
所以,我要后退一步。下面是一个简单起点的图片,我的实用程序
ViewController
(主视图控制器)和另外两个控制器(蓝色和黄色)。想象一下,当第一次显示实用程序ViewController
(主视图)时,蓝色(默认)视图将显示在粉色视图所在的位置。用户将能够点击这两个按钮来回移动,粉色视图将永远不会显示。我只想要蓝色的风景去粉色的风景,黄色的风景去粉色的风景。我希望这是有道理的。
我正在尝试使用
addChildViewController
。据我所见,有两种方法可以做到这一点:以编程方式在情节提要
或addChildViewController
中创建容器视图。我想用编程的方式来做。我不想使用NavigationController
或选项卡栏。我只想添加控制器,并在按下相关按钮时将正确的视图推入粉红色视图。
下面是我到目前为止的代码。我要做的就是在粉色视图所在的位置显示蓝色视图。根据我所看到的,我应该能够只添加
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
--------------------------编辑------------------------------
自我。关于TVC。aboutView为零。但是我把它连接到了故事板上。我还需要实例化它吗?
我看到两个问题。首先,由于您要在情节提要中创建控制器,因此应该使用instantialeviewcontrollerwhiteIdentifier:
,而不是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];
}
这篇文章可以追溯到现代iOS的早期。它使用当前信息和当前Swift语法进行更新。
iOS今天“一切都是容器观”。这是你今天制作应用程序的基本方式。
一个应用程序可能简单到只有一个屏幕。但即使在这种情况下,屏幕上的每个“东西”都是容器视图。
就这么简单。。。
版本说明
2020年。如今,您通常只需从单独的故事板加载容器视图,这非常容易。在这篇文章的底部有解释。如果您是容器视图的新手,也许可以先熟悉“经典风格”(“相同的故事板”)容器教程。
2021、更新语法。用了这么多新的####漂亮的标题。有关从代码加载的更多详细信息。
将容器视图拖到场景视图中。(就像您将拖动任何元素,如UIButton一样。)
容器视图是此图中的棕色对象。它实际上在场景视图中。
将容器视图拖动到场景视图中时,Xcode会自动提供两种功能:
>
在场景视图中获得容器视图,
你会得到一个全新的UIViewController
,它就在你故事板白色的某个地方。
这两者都与“共济会符号”有关——解释如下!
就这么简单。
你完蛋了。
这是视觉上解释的同样的事情。
请注意(A)
处的容器视图。
请注意位于(B)
的控制器。
点击B。(那是B-不是A!)
去右上方的检查员那里。注意上面写着"UIViewController"
将其更改为您自己的自定义类,即UIViewController。
因此,我有一个Swift类Snap
,它是一个UIViewController
。
在我输入“Snap”的检查器中显示“UIViewController”。
(像往常一样,当你开始输入Snap时,Xcode会自动完成Snap...)
这就是全部-你完蛋了。
所以当你点击添加容器视图时,苹果会自动给你一个链接的视图控制器,放在故事板上。
目前(2019年),默认情况下,它恰好成为一个UIViewController
。
这很愚蠢:它应该问你需要哪种类型。例如,通常需要一个表视图。
下面是如何将其更改为不同的内容:
在编写本文时,Xcode默认为您提供了一个UIViewController
。假设您想要一个UICollectionViewController
:
(i) 将容器视图拖动到场景中。查看序列图像板上的UIViewController,默认情况下Xcode为您提供该控制器。
(ii)将新的UICollectionViewController
拖动到情节提要主白色区域的任何位置。
(iii)单击场景中的容器视图。单击连接检查器。请注意,有一个“触发序列”。将鼠标移到“触发序列”上,注意Xcode高亮显示了所有不需要的UIViewController。
(iv)单击“x”以实际删除触发的序列。
(v) 从触发的序列中拖动(viewDidLoad是唯一的选择)。在情节提要上拖动到新的UICollectionViewController。放开,一个弹出窗口出现。您必须选择“嵌入”。
(vi)只需删除所有不需要的UIViewController。你完蛋了。
简短版本:
>
删除不需要的UIViewController。
将新的UICollectionViewController
放在情节提要上的任意位置。
控件从容器视图的Connections-Trigger Segue-viewDidLoad拖动到新控制器。
确保在弹出窗口中选择“嵌入”。
就这么简单。
你会有一个“正方形中的正方形”共济会符号:它在连接容器视图和视图控制器的“弯曲线”上。
“共济会符号”就是赛格。
点击“共济会符号”来选择乐段。
看你的右边。
您必须为segue键入文本标识符。
你决定名字。它可以是任何文本字符串。一个好的选择通常是"segueClassName"。
如果您遵循该模式,那么您的所有Segue将被称为segueClockView、seguePersonSelector、segueSnap、segueCards等等。
接下来,在哪里使用该文本标识符?
然后,在代码中,在整个场景的ViewController中执行以下操作。
假设场景中有三个容器视图。每个容器视图持有不同的控制器,如“快照”、“时钟”和“其他”。
最新语法
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) }
}
就这么简单。使用prepareforsgue
调用连接一个变量以引用控制器。
假设您“在”已放置在容器视图中的控制器中(示例中为“快照”)。
到达您上方的“boss”视图控制器(示例中为“破折号”)可能会让人困惑。幸运的是,这很简单:
// 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 = parent as? Dash
}
关键:仅适用于视图显示
或更高版本。在viewDidLoad
中不起作用。
你完蛋了。
提示:别忘了,这只适用于容器视图。
现在有了故事板标识符,在屏幕上弹出新视图是很平常的事(就像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的父视图控制器。
但是,当您使用InstanceDeviceController时,情况不一定如此。
非常令人困惑的是,在iOS中,父视图控制器与实例化它的类无关。(可能是相同的,但通常是不同的。)self。父模式
仅适用于容器视图。
(对于instantiateViewController模式中的类似结果,您必须使用协议和委托,记住委托将是一个弱链接。)
请注意,现在从另一个故事板动态加载容器视图非常容易——参见下面的最后一节。这通常是最好的方法。
值得注意的是,“准备就绪”是一个非常糟糕的名字!
“prepareForSegue”用于两个目的:加载容器视图,以及在场景之间进行分段。
但是在实践中,你很少在场景之间切换!然而,几乎每个应用程序都有很多很多容器视图,这是理所当然的。
如果“prepareForSegue”被称为“loadingContainerView”之类的话,那就更有意义了。
常见的情况是:屏幕上有一个小区域,您希望在其中显示多个不同视图控制器中的一个。例如,四个小部件中的一个。
最简单的方法是:在同一区域内放置四个不同的容器视图。在您的代码中,只需隐藏所有四个,然后打开希望可见的一个。
容易的
假设您有一个情节提要文件“Map.storyboard”,情节提要ID为“MapID”,并且情节提要是Map
类的视图控制器。
let map = UIStoryboard(name: "Map", bundle: nil)
.instantiateViewController(withIdentifier: "MapID")
as! Map
在你的主场景中有一个普通的UIView:
@IBOutlet var dynamicContainerView: UIView!
Apple在此解释添加动态容器视图需要做的四件事
addChild(map)
map.view.frame = dynamicContainerView.bounds
dynamicContainerView.addSubview(map.view)
map.didMove(toParent: self)
(按此顺序。)
要删除该容器视图,请执行以下操作:
map.willMove(toParent: nil)
map.view.removeFromSuperview()
map.removeFromParent()
(也按顺序排列。)就这样。
但是请注意,在该示例中,DynamicContainerView
只是一个固定视图。它不会改变或调整大小。只有当你的应用从不旋转或其他任何事情时,这才有效。通常,您必须添加四个常见的约束,以便在它调整大小时简单地将map.view保留在DynamicContainerView中。事实上,这是任何iOS应用程序都需要的“世界上最方便的扩展”,
extension UIView {
// it's basically impossible to make an iOS app without this!
func bindEdgesToSuperview() {
guard let s = superview else {
preconditionFailure("`superview` nil in bindEdgesToSuperview")
}
translatesAutoresizingMaskIntoConstraints = false
leadingAnchor.constraint(equalTo: s.leadingAnchor).isActive = true
trailingAnchor.constraint(equalTo: s.trailingAnchor).isActive = true
topAnchor.constraint(equalTo: s.topAnchor).isActive = true
bottomAnchor.constraint(equalTo: s.bottomAnchor).isActive = true
}
}
因此,在任何实际应用程序中,上述代码都是:
addChild(map)
dynamicContainerView.addSubview(map.view)
map.view.bindEdgesToSuperview()
map.didMove(toParent: self)
(有些人甚至做了一个扩展名.addSubviewAndBindEdgesToSuperview()
,以避免那里出现一行代码!)
提醒必须删除订单
您已将map
动态添加到保持架中,现在要将其删除。正确且唯一的顺序是:
map.willMove(toParent: nil)
map.view.removeFromSuperview()
map.removeFromParent()
通常情况下,您会有一个holder视图,并且您希望交换不同的控制器。因此:
var current: UIViewController? = nil
private func _install(_ newOne: UIViewController) {
if let c = current {
c.willMove(toParent: nil)
c.view.removeFromSuperview()
c.removeFromParent()
}
current = newOne
addChild(current!)
holder.addSubview(current!.view)
current!.view.bindEdgesToSuperview()
current!.didMove(toParent: self)
}
我不知道这是否是搜索“在子视图中添加UIViewController”的正确键。正如您在我的图像中看到的,有两个ViewController,主控制器和第二个控制器。主控制器内部有一个UIView(蓝色背景色)。在UIView中,我想在UIView中添加第二个ViewController。我有这个代码,但不起作用。 这是我的密码 我想知道这是否可行?我知道在xib文件中工作,我不知道在google
如何添加mathwidget作为一个子视图内另一个UIViewController目前,mathwidget工作正常时,加载UIViewController. let subViewEE=MathWidgetClassName()self.present(subViewEE,动画:真,完成:零) 但是,当我试图将其添加为当前视图控制器中的子视图时,什么都没有显示,下面是代码: 有人能帮助在当前UI
JFinalConfig 是 JFinal 的核心配置,详情: https://www.jfinal.com/doc/2-1 ,其内容如下: public class DemoConfig extends JFinalConfig { public void configConstant(Constants me) {} public void configRoute(Routes
我创建了一个几乎为空的UIViewController类,名为。在视图中,我设置标题并添加一个关闭按钮到导航我tem.leftBarButtonItem。 我的如下所示: 显示viewController时,其视图的背景为黑色。如何设置它的视图以用空视图填充屏幕——就像在故事板中设置UIViewController一样? 我已经尝试将以下内容添加到视图,但是视图仍然是黑色的:
我尝试创建自己的taglib,它扩展了现有的taglib:liferay-UI中的input-asset-links。因此,我在my-ext-web中的web-inf/tld中创建了文件liferay-ui-ext.tld,其中xml如下: 我还在web.xml中添加了以下代码: 13:48:19,661错误[http-bio-8080-exec-22][includetaG:129]当前URL/
问题内容: 我没有找到有关此问题的文章,但没有一个解决我的问题。 就像我说的那样。 ViewControllerA ViewControllerB 我试图将添加为的子视图,但是它 抛出类似“ ” 的错误。 下面是代码… ViewControllerA ViewControllerB只是一个带有标签的简单屏幕。 ViewControllerB EDIT 根据用户答案的建议解决方案,ViewCon