Add child view controller to current view controller

时间:2015-10-06 08:13:23

标签: ios objective-c uinavigationcontroller

I am trying to add a child view controller in code, to the current view controller from storyboard by using the next code:

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];

}

The view seem to be displaying on the simulator at least but in console I get a lot or error:

 <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.

And also the same description but different error:

CGContextSetLineWidth, CGContextSetLineJoin, CGContextSetLineCap, CGContextSetMiterLimit, CGContextSetFlatness, CGContextAddPath, CGContextDrawPath, CGContextRestoreGState

all these error get logged twice.

Does anyone know what I am doing wrong?

also I read a few posts and in some it was suggested to alloc and init the view controller before passing the data, I also tried that without any luck.

5 个答案:

答案 0 :(得分:27)

why you do not try this code for adding view i think this one is simple and easy..

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]; 

for further more information check this link.

答案 1 :(得分:22)

  • Configuring a Container in Interface Builder.

To create a parent-child container relationship at design time, add a container view object to your storyboard scene, as shown in image below. A container view object is a placeholder object that represents the contents of a child view controller. Use that view to size and position the child’s root view in relation to the other views in the container.

enter image description here

When you load a view controller with one or more container views, Interface Builder also loads the child view controllers associated with those views. The children must be instantiated at the same time as the parent so that the appropriate parent-child relationships can be created.

If you do not use Interface Builder to set up your parent-child container relationships, you must create those relationships programmatically by adding each child to the container view controller, as described in Adding a Child View Controller to Your Content.

  • Adding a Child View Controller to Your Content.

To incorporate a child view controller into your content programmatically, create a parent-child relationship between the relevant view controllers by doing the following:

  1. Call the addChildViewController: method of your container view controller. This method tells UIKit that your container view controller is now managing the view of the child view controller.
  2. Add the child’s root view to your container’s view hierarchy. Always remember to set the size and position of the child’s frame as part of this process.
  3. Add any constraints for managing the size and position of the child’s root view.
  4. Call the didMoveToParentViewController: method of the child view controller.

Here is the code for that.

- (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)

}

More detail explanation of the same example is given at Apple developer programming guide.

答案 2 :(得分:8)

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)

注意:

  • 故事板名称是&#34; Main&#34;。
  • 在故事板中查看控制器标识符命名为&#34; LOGIN&#34;。
  • 这使用故事板来创建加载视图控制器,但同样可以通过编程方式完成。在尝试访问视图的框架之前,只需确保将视图加载到内存中,否则会出现崩溃(执行类似于视图控制器的操作)。

答案 3 :(得分:6)

didMoveToParentViewController must be the last.

答案 4 :(得分:0)

您还可以创建用于添加和删除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()
    }
}

只要您想在UIViewController方法中添加viewDidLoad(),就需要调用addChildViewControllerWithView(someVC)