【问题标题】:Add child view controller to current view controller将子视图控制器添加到当前视图控制器
【发布时间】:2016-01-03 01:41:56
【问题描述】:

我正在尝试使用以下代码将代码中的子视图控制器添加到情节提要中的当前视图控制器:

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

所有这些错误都会被记录两次。

有谁知道我做错了什么?

我还阅读了一些帖子,其中一些建议在传递数据之前分配和初始化视图控制器,我也尝试过,但没有任何运气。

【问题讨论】:

  • 你不需要这条线LogInTutorialViewController *lvc = [[LogInTutorialViewController alloc] init];,因为你是从故事板实例化的。对于下面的错误检查答案,我相信您的订单不正确。
  • 是的,我知道,但我只是按照建议的帖子尝试过

标签: ios objective-c uinavigationcontroller


【解决方案1】:

您还可以创建一个扩展来添加和删除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)

【讨论】:

    【解决方案2】:
    • 在 Interface Builder 中配置容器。

    要在设计时创建父子容器关系,请将容器视图对象添加到情节提要场景中,如下图所示。容器视图对象是一个占位符对象,表示子视图控制器的内容。使用该视图相对于容器中的其他视图来调整子视图的大小和位置。

    当您加载具有一个或多个容器视图的视图控制器时,Interface Builder 还会加载与这些视图关联的子视图控制器。子项必须与父项同时实例化,以便创建适当的父子关系。

    如果您不使用 Interface Builder 设置父子容器关系,则必须通过将每个子视图控制器添加到容器视图控制器以编程方式创建这些关系,如将子视图控制器添加到您的内容中所述。

    • 将子视图控制器添加到您的内容中。

    要以编程方式将子视图控制器合并到您的内容中,请通过执行以下操作在相关视图控制器之间创建父子关系:

    1. 调用容器视图控制器的addChildViewController: 方法。 这个方法告诉 UIKit 你的容器视图控制器现在正在管理子视图控制器的视图。
    2. 将子视图的根视图添加到容器的视图层次结构中。 永远记得在这个过程中设置孩子框架的大小和位置。
    3. 添加任何约束以管理子视图的大小和位置。
    4. 调用子视图控制器的 didMoveToParentViewController: 方法。

    这是代码。

    - (void)displayContentController:(UIViewController *)content {
        [self addChildViewController:content];
        content.view.frame = [self frameForContentController];
        [self.view addSubview:self.currentClientView];
        [content didMoveToParentViewController:self];
    }
    

    斯威夫特

    func displayContentController(_ content: UIViewController?) {
    if let content = content {
        addChild(content)
    }
    content?.view.frame = frameForContentController()
    view.addSubview(currentClientView)
    content?.didMove(toParent: self)
    

    }

    Apple developer programming guide 给出了同一示例的更详细说明。

    【讨论】:

    • 我贴的代码和你回答的有什么区别?
    • 你的代码行和我的代码行的顺序
    • 什么是currentClientView?
    • 那么你正在做的是: [self.view addSubview: self.view] 女巫是错误的,或者你正在做 [self.view addSubview: content.view] 女巫与我的代码相同...
    【解决方案3】:

    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”。
    • 这使用故事板来创建加载视图控制器,但同样可以通过编程完成。在您尝试访问视图的框架之前,请确保视图已加载到内存中,否则您将遇到崩溃(执行一些操作,例如以模态方式显示视图控制器)。

    【讨论】:

    • 谢谢,这个解决方案在 swift 4 中很有效
    【解决方案4】:

    为什么你不尝试这个代码来添加视图我认为这个很简单......

    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

    【讨论】:

    • 让我失望的部分是必须明确地将原点设置为零。这个[self.loginView.view setFrame:self.contentView.frame] 不会在我的视图中正确设置它,因为我的contentView 有一个UINavigationBar,所以contentView.frame.origin.y 是64,因此将self.loginView 向下推。谢谢!
    • 这个答案有 15+ 票,接受的答案有 13 票。所以我认为这个答案必须是一个公认的答案。 :)
    【解决方案5】:

    didMoveToParentViewController 必须是最后一个。

    【讨论】:

    • 当我到达该行时,所有错误都会被记录:[content.view setFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds。大小.高度)];
    • 尝试先添加子视图,然后设置它的框架。
    • 现在我怀疑您的问题与子视图控制器视图中的内容有关,而不是与父子关系有关。
    • 尝试了下一个代码:[self addChildViewController:content]; [self.view addSubview:content.view]; [内容 didMoveToParentViewController:self]; [content.view setFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height)];而且我现在仍然在 didMoveToParent 行上记录了错误
    • LogInTutorialViewController 视图里面有什么?看起来它有一些绘图问题。
    猜你喜欢
    • 1970-01-01
    • 2013-06-05
    • 1970-01-01
    • 2023-03-11
    • 2021-11-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-17
    相关资源
    最近更新 更多