在另一个视图控制器中添加视图控制器作为子视图
我找到了这个问题的几篇文章,但没有一篇解决了我的问题。在另一个视图控制器中添加视图控制器作为子视图
说我好象..
- ViewControllerA
- ViewControllerB
我试图ViewControllerB添加为ViewControllerA一个子视图,但是,它抛出一个错误,如 “fatal error: unexpectedly found nil while unwrapping an Optional value
”。
下面是代码...
ViewControllerA
var testVC: ViewControllerB = ViewControllerB();
override func viewDidLoad()
{
super.viewDidLoad()
self.testVC.view.frame = CGRectMake(0, 0, 350, 450);
self.view.addSubview(testVC.view);
// Do any additional setup after loading the view.
}
ViewControllerB仅仅是一个简单的屏幕,在它的标签。
ViewControllerB
@IBOutlet weak var test: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
test.text = "Success" // Throws ERROR here "fatal error: unexpectedly found nil while unwrapping an Optional value"
}
EDIT
随着来自用户的答案的建议的解决方案,在ViewControllerB ViewControllerA会在屏幕上。灰色边框是我为子视图创建的框架。
一对夫妇的意见:
-
当你实例第二个视图控制器,您呼叫
ViewControllerB()
。如果该视图控制器以编程方式创建其视图(这是不寻常的),那就没问题了。但是IBOutlet
的存在表明这个第二个视图控制器的场景是在Interface Builder中定义的,但是通过调用ViewControllerB()
,您不会给故事板一个实例化该场景并挂接所有插座的机会。因此,隐含地解包UILabel
是nil
,导致您的错误消息。取而代之,您希望在Interface Builder中为您的目标视图控制器提供“故事板ID”,然后您可以使用
instantiateViewController(withIdentifier:)
实例化它(并挂接所有IB插座)。在斯威夫特3:let controller = storyboard!.instantiateViewController(withIdentifier: "scene storyboard id")
您现在可以访问此
controller
的view
。但如果你真的想要做addSubview
(即你没有转换到下一个场景),那么你正在进行一种叫做“视图控制器控制”的练习。你不只是想简单地addSubview
。你想要做一些额外的容器视图控制器调用,例如:let controller = storyboard.instantiateViewController(withIdentifier: "scene storyboard id") addChildViewController(controller) controller.view.frame = ... // or better, turn off `translatesAutoresizingMaskIntoConstraints` and then define constraints for this subview view.addSubview(controller.view) controller.didMove(toParentViewController: self)
有关为什么这个
addChildViewController
和didMove(toParentViewController:)
是必要的,看到WWDC 2011 video #102 - Implementing UIViewController Containment更多信息。简而言之,您需要确保您的视图控制器层次结构与您的视图层次结构保持同步,并且这些对addChildViewController
和didMove(toParentViewController:)
的调用确保这种情况。另请参阅“视图控制器编程指南”中的Creating Custom Container View Controllers。
顺便说一句,上面说明了如何以编程方式做到这一点。如果您在Interface Builder中使用“容器视图”,实际上它会容易得多。
那么你不必担心这些遏制相关的电话,和Interface Builder会照顾它。
对于Swift 2的实现,请参阅previous revision of this answer。
感谢Rob。 添加详细语法你的第二个观察:
let controller:MyView = self.storyboard!.instantiateViewControllerWithIdentifier("MyView") as! MyView
controller.ANYPROPERTY=THEVALUE // If you want to pass value
controller.view.frame = self.view.bounds;
controller.willMoveToParentViewController(self)
self.view.addSubview(controller.view)
self.addChildViewController(controller)
controller.didMoveToParentViewController(self)
,并删除了视图 - 控制:
self.willMoveToParentViewController(nil)
self.view.removeFromSuperview()
self.removeFromParentViewController()
顺便说一句,当调用'addChildViewController'时,不_调用'willMoveToParentViewController'。调用'addChildViewController'会为你调用它。请参阅_View中的[添加和删除子项](https://developer.apple.com/library/ios/featuredarticles/ViewControllerPGforiPhoneOS/CreatingCustomContainerViewControllers/CreatingCustomContainerViewControllers.html#//apple_ref/doc/uid/TP40007457-CH18-SW13)针对iOS的控制器编程指南_因此,我个人总是在实例化之后立即调用'addChildViewController',但在配置它之前。 – Rob 2015-08-17 12:47:45
当你做的controller.ANYPROPERTY = THEVALUE ..我猜AnyProperty是在childViewController中定义的。我试过了,它给了我一个错误。任何想法如何纠正。 – 2015-10-08 08:15:16
@Anuj Arora你的猜测是对的。 ANYPROPERTY在子viewController中定义。您可以在子ViewController中检查ANYPROPERTY,但在ViewDidAppear中不检查ViewDidLoad中的ANYPROPERTY。 – Sunita 2016-05-19 11:17:01
同时请参阅官方文档上实现自定义的容器视图控制器:
本文档包含每条指令的更多详细信息还介绍了如何添加转换。
翻译斯威夫特3:
func cycleFromViewController(oldVC: UIViewController,
newVC: UIViewController) {
// Prepare the two view controllers for the change.
oldVC.willMove(toParentViewController: nil)
addChildViewController(newVC)
// Get the start frame of the new view controller and the end frame
// for the old view controller. Both rectangles are offscreen.r
newVC.view.frame = view.frame.offsetBy(dx: view.frame.width, dy: 0)
let endFrame = view.frame.offsetBy(dx: -view.frame.width, dy: 0)
// Queue up the transition animation.
self.transition(from: oldVC, to: newVC, duration: 0.25, animations: {
newVC.view.frame = oldVC.view.frame
oldVC.view.frame = endFrame
}) { (_: Bool) in
oldVC.removeFromParentViewController()
newVC.didMove(toParentViewController: self)
}
}
FUNC callForMenuView(){
if(!isOpen)
{
isOpen = true
let menuVC : MenuViewController = self.storyboard!.instantiateViewController(withIdentifier: "menu") as! MenuViewController
self.view.addSubview(menuVC.view)
self.addChildViewController(menuVC)
menuVC.view.layoutIfNeeded()
menuVC.view.frame=CGRect(x: 0 - UIScreen.main.bounds.size.width, y: 0, width: UIScreen.main.bounds.size.width-90, height: UIScreen.main.bounds.size.height);
UIView.animate(withDuration: 0.3, animations: {() -> Void in
menuVC.view.frame=CGRect(x: 0, y: 0, width: UIScreen.main.bounds.size.width-90, height: UIScreen.main.bounds.size.height);
}, completion:nil)
}else if(isOpen)
{
isOpen = false
let viewMenuBack : UIView = view.subviews.last!
UIView.animate(withDuration: 0.3, animations: {() -> Void in
var frameMenu : CGRect = viewMenuBack.frame
frameMenu.origin.x = -1 * UIScreen.main.bounds.size.width
viewMenuBack.frame = frameMenu
viewMenuBack.layoutIfNeeded()
viewMenuBack.backgroundColor = UIColor.clear
}, completion: { (finished) -> Void in
viewMenuBack.removeFromSuperview()
})
}
感谢您的详细解释。当我尝试将'ViewControllerB'添加到'ViewControllerA'时,'ViewControllerB'正在关闭屏幕。我用模拟器的屏幕截图编辑了我的帖子。 – 2014-12-04 17:01:15
这是可能的。这就是为什么,在我的例子中,我手动设置了“框架”。或者,如果你关闭了'translatesFrameIntoConstraints'(或者其他所谓的),你也可以通过编程来添加约束条件。但是,如果您添加子视图,则需要负责设置其框架,就像您使用所有以编程方式添加的子视图一样。 – Rob 2014-12-04 18:31:58
这是如何添加边界controller.view.frame = UIScreen.mainScreen()。bounds' – 2016-03-03 09:14:53