将子视图控制器添加到当前视图控制器
Add child view controller to current view controller
我正在尝试使用下一个代码在代码中将子视图控制器添加到情节提要中的当前视图控制器:
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle: nil];
LogInTutorialViewController *lvc = [[LogInTutorialViewController alloc] init];
lvc = (LogInTutorialViewController *)[storyboard instantiateViewControllerWithIdentifier:@"LogInTutorialViewControllerID"];
[self displayContentController:lvc];
- (void) displayContentController: (LogInTutorialViewController*) content;
{
//add as childViewController
[self addChildViewController:content];
[content didMoveToParentViewController:self];
[content.view setFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height)];
[self.view addSubview:content.view];
}
视图似乎至少显示在模拟器上,但在控制台中我得到很多或错误:
<Error>: CGContextSaveGState: invalid context 0x0. This is a serious error. This application, or a library it uses, is using an invalid context and is thereby contributing to an overall degradation of system stability and reliability. This notice is a courtesy: please fix this problem. It will become a fatal error in an upcoming update.
同样的描述但不同的错误:
CGContextSetLineWidth、CGContextSetLineJoin、CGContextSetLineCap、CGContextSetMiterLimit、CGContextSetFlatness、CGContextAddPath、CGContextDrawPath、CGContextRestoreGState
所有这些错误都被记录了两次。
有谁知道我做错了什么吗?
我也读了一些帖子,有些帖子建议在传递数据之前分配和初始化视图控制器,我也尝试过但没有任何运气。
didMoveToParentViewController 必须是最后一个。
为什么你不试试这个添加视图的代码我认为这个很简单..
self.loginView = [self.storyboard instantiateViewControllerWithIdentifier:@"LOGIN"];
[self addChildViewController:self.loginView];
[self.loginView.view setFrame:CGRectMake(0.0f, 0.0f, self.contentView.frame.size.width, self.contentView.frame.size.height)];
[self.contentView addSubview:self.loginView.view];
[self.loginView didMoveToParentViewController:self];
有关更多信息,请查看此 link。
- 在 Interface Builder 中配置容器。
要在设计时创建 parent-child 容器关系,请将容器视图 object 添加到故事板场景中,如下图所示。容器视图 object 是一个占位符 object,代表 child 视图控制器的内容。使用该视图相对于容器中的其他视图调整 child 的根视图的大小和位置。
当您使用一个或多个容器视图加载视图控制器时,Interface Builder 还会加载与这些视图关联的 child 视图控制器。 children 必须与 parent 同时实例化,以便可以创建适当的 parent-child 关系。
如果您不使用 Interface Builder 来设置您的 parent-child 容器关系,则必须通过将每个 child 添加到容器视图控制器以编程方式创建这些关系,如添加 Child 查看您的内容的控制器。
- 向您的内容添加 Child 视图控制器。
要以编程方式将 child 视图控制器合并到您的内容中,请通过执行以下操作在相关视图控制器之间创建 parent-child 关系:
- 调用容器视图控制器的
addChildViewController:
方法。
这个方法告诉 UIKit 你的容器视图控制器现在正在管理 child 视图控制器的视图。
- 将 child 的根视图添加到容器的视图层次结构中。
始终记得在此过程中设置 child 框架的大小和位置。
- 添加任何约束以管理 child 的根视图的大小和位置。
- 调用 child 视图控制器的 didMoveToParentViewController: 方法。
这是相关代码。
- (void)displayContentController:(UIViewController *)content {
[self addChildViewController:content];
content.view.frame = [self frameForContentController];
[self.view addSubview:self.currentClientView];
[content didMoveToParentViewController:self];
}
Swift:
func displayContentController(_ content: UIViewController?) {
if let content = content {
addChild(content)
}
content?.view.frame = frameForContentController()
view.addSubview(currentClientView)
content?.didMove(toParent: self)
}
给出了同一示例的更多详细说明
Swift中的解决方案(Swift 4 在撰写本文时):
//load the view controller and add as child
storyboard = UIStoryboard(name: "Main", bundle: Bundle.main)
loginVC = storyboard.instantiateViewController(withIdentifier: "LOGIN")
addChildViewController(loginVC)
//make sure that the child view controller's view is the right size
loginVC.view.frame = contentView.bounds
contentView.addSubview(loginVC.view)
//you must call this at the end per Apple's documentation
loginVC.didMove(toParentViewController: self)
备注:
- 故事板名称是 "Main"。
- 故事板中的视图控制器标识符名为 "LOGIN"。
- 这使用故事板来创建加载视图控制器,但同样可以通过编程方式完成。在您尝试访问视图的框架之前,请确保视图已加载到内存中,否则您将崩溃(执行类似以模态方式呈现视图控制器的操作)。
您还可以创建用于添加和删除的扩展 UIViewController
。
extension UIViewController {
func addChildViewControllerWithView(_ childViewController: UIViewController, toView view: UIView? = nil) {
let view: UIView = view ?? self.view
childViewController.removeFromParent()
childViewController.willMove(toParent: self)
addChild(childViewController)
childViewController.didMove(toParent: self)
childViewController.view.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(childViewController.view)
view.addConstraints([
NSLayoutConstraint(item: childViewController.view!, attribute: .top, relatedBy: .equal, toItem: view, attribute: .top, multiplier: 1, constant: 0),
NSLayoutConstraint(item: childViewController.view!, attribute: .bottom, relatedBy: .equal, toItem: view, attribute: .bottom, multiplier: 1, constant: 0),
NSLayoutConstraint(item: childViewController.view!, attribute: .leading, relatedBy: .equal, toItem: view, attribute: .leading, multiplier: 1, constant: 0),
NSLayoutConstraint(item: childViewController.view!, attribute: .trailing, relatedBy: .equal, toItem: view, attribute: .trailing, multiplier: 1, constant: 0)
])
view.layoutIfNeeded()
}
func removeChildViewController(_ childViewController: UIViewController) {
childViewController.removeFromParent()
childViewController.willMove(toParent: nil)
childViewController.removeFromParent()
childViewController.didMove(toParent: nil)
childViewController.view.removeFromSuperview()
view.layoutIfNeeded()
}
}
每当您想在 viewDidLoad()
方法中添加 UIViewController
时,您需要调用 addChildViewControllerWithView(someVC)
我正在尝试使用下一个代码在代码中将子视图控制器添加到情节提要中的当前视图控制器:
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle: nil];
LogInTutorialViewController *lvc = [[LogInTutorialViewController alloc] init];
lvc = (LogInTutorialViewController *)[storyboard instantiateViewControllerWithIdentifier:@"LogInTutorialViewControllerID"];
[self displayContentController:lvc];
- (void) displayContentController: (LogInTutorialViewController*) content;
{
//add as childViewController
[self addChildViewController:content];
[content didMoveToParentViewController:self];
[content.view setFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height)];
[self.view addSubview:content.view];
}
视图似乎至少显示在模拟器上,但在控制台中我得到很多或错误:
<Error>: CGContextSaveGState: invalid context 0x0. This is a serious error. This application, or a library it uses, is using an invalid context and is thereby contributing to an overall degradation of system stability and reliability. This notice is a courtesy: please fix this problem. It will become a fatal error in an upcoming update.
同样的描述但不同的错误:
CGContextSetLineWidth、CGContextSetLineJoin、CGContextSetLineCap、CGContextSetMiterLimit、CGContextSetFlatness、CGContextAddPath、CGContextDrawPath、CGContextRestoreGState
所有这些错误都被记录了两次。
有谁知道我做错了什么吗?
我也读了一些帖子,有些帖子建议在传递数据之前分配和初始化视图控制器,我也尝试过但没有任何运气。
didMoveToParentViewController 必须是最后一个。
为什么你不试试这个添加视图的代码我认为这个很简单..
self.loginView = [self.storyboard instantiateViewControllerWithIdentifier:@"LOGIN"];
[self addChildViewController:self.loginView];
[self.loginView.view setFrame:CGRectMake(0.0f, 0.0f, self.contentView.frame.size.width, self.contentView.frame.size.height)];
[self.contentView addSubview:self.loginView.view];
[self.loginView didMoveToParentViewController:self];
有关更多信息,请查看此 link。
- 在 Interface Builder 中配置容器。
要在设计时创建 parent-child 容器关系,请将容器视图 object 添加到故事板场景中,如下图所示。容器视图 object 是一个占位符 object,代表 child 视图控制器的内容。使用该视图相对于容器中的其他视图调整 child 的根视图的大小和位置。
当您使用一个或多个容器视图加载视图控制器时,Interface Builder 还会加载与这些视图关联的 child 视图控制器。 children 必须与 parent 同时实例化,以便可以创建适当的 parent-child 关系。
如果您不使用 Interface Builder 来设置您的 parent-child 容器关系,则必须通过将每个 child 添加到容器视图控制器以编程方式创建这些关系,如添加 Child 查看您的内容的控制器。
- 向您的内容添加 Child 视图控制器。
要以编程方式将 child 视图控制器合并到您的内容中,请通过执行以下操作在相关视图控制器之间创建 parent-child 关系:
- 调用容器视图控制器的
addChildViewController:
方法。 这个方法告诉 UIKit 你的容器视图控制器现在正在管理 child 视图控制器的视图。 - 将 child 的根视图添加到容器的视图层次结构中。 始终记得在此过程中设置 child 框架的大小和位置。
- 添加任何约束以管理 child 的根视图的大小和位置。
- 调用 child 视图控制器的 didMoveToParentViewController: 方法。
这是相关代码。
- (void)displayContentController:(UIViewController *)content {
[self addChildViewController:content];
content.view.frame = [self frameForContentController];
[self.view addSubview:self.currentClientView];
[content didMoveToParentViewController:self];
}
Swift:
func displayContentController(_ content: UIViewController?) {
if let content = content {
addChild(content)
}
content?.view.frame = frameForContentController()
view.addSubview(currentClientView)
content?.didMove(toParent: self)
}
给出了同一示例的更多详细说明Swift中的解决方案(Swift 4 在撰写本文时):
//load the view controller and add as child
storyboard = UIStoryboard(name: "Main", bundle: Bundle.main)
loginVC = storyboard.instantiateViewController(withIdentifier: "LOGIN")
addChildViewController(loginVC)
//make sure that the child view controller's view is the right size
loginVC.view.frame = contentView.bounds
contentView.addSubview(loginVC.view)
//you must call this at the end per Apple's documentation
loginVC.didMove(toParentViewController: self)
备注:
- 故事板名称是 "Main"。
- 故事板中的视图控制器标识符名为 "LOGIN"。
- 这使用故事板来创建加载视图控制器,但同样可以通过编程方式完成。在您尝试访问视图的框架之前,请确保视图已加载到内存中,否则您将崩溃(执行类似以模态方式呈现视图控制器的操作)。
您还可以创建用于添加和删除的扩展 UIViewController
。
extension UIViewController {
func addChildViewControllerWithView(_ childViewController: UIViewController, toView view: UIView? = nil) {
let view: UIView = view ?? self.view
childViewController.removeFromParent()
childViewController.willMove(toParent: self)
addChild(childViewController)
childViewController.didMove(toParent: self)
childViewController.view.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(childViewController.view)
view.addConstraints([
NSLayoutConstraint(item: childViewController.view!, attribute: .top, relatedBy: .equal, toItem: view, attribute: .top, multiplier: 1, constant: 0),
NSLayoutConstraint(item: childViewController.view!, attribute: .bottom, relatedBy: .equal, toItem: view, attribute: .bottom, multiplier: 1, constant: 0),
NSLayoutConstraint(item: childViewController.view!, attribute: .leading, relatedBy: .equal, toItem: view, attribute: .leading, multiplier: 1, constant: 0),
NSLayoutConstraint(item: childViewController.view!, attribute: .trailing, relatedBy: .equal, toItem: view, attribute: .trailing, multiplier: 1, constant: 0)
])
view.layoutIfNeeded()
}
func removeChildViewController(_ childViewController: UIViewController) {
childViewController.removeFromParent()
childViewController.willMove(toParent: nil)
childViewController.removeFromParent()
childViewController.didMove(toParent: nil)
childViewController.view.removeFromSuperview()
view.layoutIfNeeded()
}
}
每当您想在 viewDidLoad()
方法中添加 UIViewController
时,您需要调用 addChildViewControllerWithView(someVC)