【问题标题】:View Controller Containment when using Interface Builder使用 Interface Builder 时查看控制器包含
【发布时间】:2014-08-19 14:41:21
【问题描述】:

我正在尝试使用 Interface Builder 定义一系列容器视图控制器(可能是我的第一个错误)。在情节提要中,我创建了顶视图控制器,添加了 3 个容器视图,它们会自动将每个子视图控制器添加到情节提要中。我为每个容器视图添加了一个出口,并且能够通过隐藏/显示容器视图成功地操纵子视图。代码真的不多说了,就是:

-(IBAction) button1Pushed:(id)sender
{
     containerView2.hidden = true;
     containerView1.hidden = false;
}

虽然可行,但我需要更新每次放映的内容。 viewWillAppear(和相关函数)仅在初始创建时触发子视图控制器,而不是在隐藏/显示容器时触发。我想我可以添加如下内容:

    [childVC1 updateContent];
    containerView1.hidden = false;

但我希望我可以依赖 viewWillAppear(和相关功能)。我尝试了一些成功的事情,但有几个问题:

  1. 我了解 Apple 编程指南中手动创建容器的示例:
 [self addChildViewController:content];                 // 1
 [self.view addSubview:self.currentClientView];
 [content didMoveToParentViewController:self];          // 3

但这在使用 IB 时如何应用?该编程指南中没有提到IB。 IB 必须调用 addChildViewController,因为我可以使用 [self childViewControllers] 找到所有容器 VC。但是由于 viewWillAppear 只在创建时发生,这是否意味着 IB 没有继续添加视图?

所以问题1是:通过Interface Builder添加容器视图时,IB处理了多少示例代码,我需要实现多少?

  1. 作为实验,我在父级的viewDidLoad中添加了这段代码:
for ( UIViewController *vc in [self childViewControllers])
{
    [self.view addSubview:vc.view];
    [vc didMoveToParentViewController:self];
}

这导致每个子视图都同时出现在屏幕左上角。它不再尊重 IB 布局,毫不奇怪,也不再尊重显示/隐藏 containerView。我可以控制它们

 vc.view.hidden = true;

但它们已移动到某个默认位置。我可以手动重置它们的坐标,但首先使用 IB 的原因之一是避免通过代码进行屏幕定位。

问题 #2 是:在 IB 中添加容器视图时,我应该如何在仍然尊重 IB 布局的同时管理显示子项?通过操纵容器视图的出口?通过操作子视图控制器(通过 [self childViewControllers] 找到)?还是别的什么?

归根结底,我想要的状态是:

  1. 在 IB 中为父级和子级定义屏幕布局和位置
  2. 根据用户选择的按钮隐藏/显示子项
  3. viewWillAppear 在每次显示孩子时触发,允许我更新内容

感谢任何有关达到此状态的建议,谢谢!

【问题讨论】:

    标签: ios objective-c ios7 uiview uiviewcontroller


    【解决方案1】:

    答案 1:当您通过情节提要添加子视图控制器(在本例中称为容器视图)时,子视图控制器将通过 segues 添加。不,这不是通常意义上的 segue,您推送或呈现视图控制器,但在您的“超级”视图控制器中调用的方法是 prepareForSegue。在 interface builder 中,您可以像普通 segue 一样命名两个控制器之间的连接,并在此实例中获取对视图控制器的引用。这代替了 addChildViewController、didMoveToParent 等的整个舞蹈。

    答案二:我认为解决您想要的状态是有意义的。我看起来你已经解决了#1 和#2。至于让 viewWillAppear 再次触发,你必须让你的父母 viewWillAppear 再次触发,方法是推送和弹出一个新的 VC 或展示和解雇一个。仅仅因为你将它设置为隐藏然后取消隐藏它不会让它再次触发(隐藏基本上告诉绘图系统不渲染它)。

    推荐的方法(来自 Apple,请原谅我不知道链接)是通过 updateViewContraints 或 layoutSubviews 在视图子类中进行所有更新。在视图控制器世界中,类似的方法是 ViewDidLayoutSubviews。您可以通过调用 [yourViewController.view setsNeedsLayout] 向您的视图发出信号,表明它需要再次布局。作为参考,请查看 UIView 上关于 needsLayout 的文档。

    当您按下按钮以取消隐藏您的 viewController 时,您可能想要做的事情类似于:

    1:在 viewController 上设置更新其内容的任何属性或调用方法

    2:在 viewControllers 视图上调用 setsNeedsLayout

    3:取消隐藏。

    【讨论】:

      【解决方案2】:

      viewWillAppear 不会在每次显示孩子时触发。调整思路。

      当您在 IB 中创建容器视图和子视图时,它会设置一个嵌入 segue 以链接到子视图控制器。

      我建议您为每个子视图控制器添加唯一的 segue 标识符,然后在 prepareForSegue 中,使用 if/else if/else if 语句来匹配每个 segue ID。当您找到一个 segue Id 时,将该子视图控制器保存在父级的属性中:

      - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
      {
        if ([segue.identifier isEqualToString: @"firstChildID")
          self.firstChildVC =   (FirstChildVC *) segue.destinationViewController;
        else if ([segue.identifier isEqualToString: @"secondChildID")
          self.secondChildVC =   (SecondChildVC *) segue.destinationViewController;
        else if ([segue.identifier isEqualToString: @"thirdChildID")
          self.thirdChildVC =   (ThirdChildVC *) segue.destinationViewController;
      }
      

      然后定义一个用于与子视图控制器通信的协议,告诉它们它们正在被显示:

      @protocol ChildVCProtocol
      
      - (void) getReadyToShowView;
      //whatever other methods
      @end
      

      然后让您的每个子 VC 都符合该协议。将您的代码准备好在 getReadyToShowView 方法中显示。每次使子 VC 可见时调用该方法。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2022-07-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多