使用scrollview中的动态大小控制器调整容器视图的大小


73

我正在尝试在UIScrollView内创建一个具有动态高度的控制器的容器视图,并使用自动布局自动调整其大小。

演示图板的设置

视图控制器A是滚动视图,其中包括容器视图,以及下面的更多内容。

View Controller B是我希望具有动态大小的视图控制器,并且所有内容都将在View Controller A的“滚动视图”中以全高度显示。

我在获取B的动态大小以自动设置A中的Container View的大小时遇到​​了一些问题。但是,如果我在A中的Container View上设置了高度限制A中的容器视图,例如250

如果View Controller B的高度也为250,则将是预期的输出。对于高度1000,它也可以正常工作,据我所知,所有自动布局约束均已正确设置。不幸的是,由于高度实际上应该是动态的,因此我想完全避免设置高度限制。

我不确定是否有视图控制器BI可以设置任何设置来根据其内容自动更新其大小,或者我是否错过了其他技巧。任何帮助将非常感激!

是否可以在不设置高度约束的情况下根据View Controller B的大小来调整A中的Container View的大小?


您可以将高度限制设置为IBOutlet并在代码中动态调整它们
Randy

这是我最接近的解决方案,但这是最简单的方法吗?我希望有一些我想念的东西比手动设置高度约束更容易解决。
TemptingFriendlyGrison

1
我认为您也可以在此处使用preferredContentSize-不断更改它,您知道吗?
Fattie

Answers:


116

是的,有。我设法在自己的一个项目中实现了这种行为。

您要做的就是告诉系统它不应添加模仿在Interface Builder中为根视图设置固定框架的约束。触发嵌入Segue的最佳方法是在容器视图控制器中:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    // You might want to check if this is your embed segue here
    // in case there are other segues triggered from this view controller. 
    segue.destinationViewController.view.translatesAutoresizingMaskIntoConstraints = NO;
}

重要:

您必须确保加载到容器中的视图从上到下受约束,并且需要将垂直约束之一的优先级设置为小于1000的值。(始终使用底部约束是一种很好的做法为此。)这是必要的,因为否则Interface Builder会抱怨-有充分的理由:

在设计时,您的根视图具有固定的大小(高度)。现在,如果所有子视图都具有固定的高度并连接了具有相同优先级的固定约束,则除非您的固定根视图的高度恰好与子视图的总高度和垂直约束完全匹配,否则不可能满足所有这些要求。如果将其中一个约束的优先级降低到999,Interface Builder将知道打破哪个约束。但是,在运行时translatesAutoresizingMaskIntoConstraints(如上所述设置属性时),根视图不再具有固定框架,系统将改为使用999优先级约束。

界面生成器截图


2
效果很好,谢谢!在滚动视图的编辑器中存在一些约束问题,但是如果我在构建时删除的容器上设置了高度约束,则可以解决这些问题。
TemptingFriendlyGrison

14
如果您转到Interface Builder中的Size Inspector,向下滚动并从Innernsic Content Size下拉列表中选择“占位符”,则应该能够解决这些约束问题而不必在容器视图上设置和删除约束。然后,您可以为容器视图设置固定的固有大小,该大小只能由Interface Builder用来布局视图,而不能在运行时应用。
Mischa

在iOS 9上工作时,我发现在PARENT视图控制器(而不是子容器VC)中设置了translatesAutoresizingMaskIntoConstraints = NO可以解决问题。我将底部约束优先级保持在1000,这使整个容器视图得以扩展。否则,容器视图的内容将超出容器视图的底部,并且我会在布局中看到其他怪异之处。感谢您弄清楚这一点!!!
Kento

这对我不起作用,采取iboutlet容器视图并调整高度工作
siva krishna

很大的帮助!很感谢!
gunjot singh

26

从@Mischa的答案中,我能够根据其内容来使containerView的高度动态化:

在containerView的viewController中编写:

  override func loadView() {
    super.loadView()
    view.translatesAutoresizingMaskIntoConstraints = false
  }

并注意设置IB中的垂直约束。这样做无需从视图控制器外部设置view.translatesAutoresizingMaskIntoConstraints = false。

就我而言,我试图将容器的大小调整为viewController内部的tableView。因为tableView的高度取决于其父视图(因此对于IB来说一切正常),所以我通过执行以下操作完成了代码中的垂直约束:

  @IBOutlet private var tableView: UITableView! {
    didSet {
      tableView.addConstraint(tableViewHeight)
    }
  }
  private lazy var tableViewHeight: NSLayoutConstraint = NSLayoutConstraint(item: self.tableView, attribute: NSLayoutAttribute.Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1, constant: 0)

然后观察tableview的contentSize高度,并在需要时以编程方式调整tableViewHeight约束的常数。


感谢@acecilia,这确实是一个很好的提示。干杯
Fattie

17

斯威夫特4,Xcode 9

仅接受的答案并不能解决我的问题。

我的层次结构:ScrollView->内容视图(UIView)->视图| 容器视图 其他观点。

我必须添加以下约束以使ScrollView和Container能够动态调整:

  1. ScrollView:顶部,底部,前导,尾随到Superview(安全区域)
  2. 内容视图:顶部,底部,前导,尾随,等宽到ScrollView,但也具有等高(约束优先级较低:250)
  3. 视图:正常的自动布局约束。
  4. 容器视图:顶部,底部至邻居视图,前移和后移到安全区域。
  5. 容器视图的嵌入式VC:将所有约束垂直连接,将底部约束设置为较低的优先级,但大于内容视图的等高高度!在这种情况下,优先权为500
  6. 设定view.translatesAutoresizingMaskIntoConstraints = false其中一个prepareForSegue()loadView()其他陈述的答案。

现在,我在自动调整大小的滚动视图内有一个可动态调整的容器视图。


嗨,特奥多(Teodor),我读了您的回答,我认为您可以为我解决问题:stackoverflow.com/questions/48797508/twitter-profile-effect感谢您的帮助。
delarcomarta

有GitHub示例吗?
穆罕默德·哈桑

当ContainerView中有可滚动视图时,它不起作用
Hamid Shahsavari,

如果可以的话,我将投票5次。这个循序渐进的答案很简单,解决了IB约束3个小时的麻烦。
TM Lynch

惊人的解决方案!为我工作。但是我现在看到另一个问题。我的嵌入式表视图控制器就地滚动,但是滚动视图已停止滚动
jerry

4

在@Mischa解决此问题的出色方法的基础上,如果容器嵌入了动态大小的UITableView,则需要查看覆盖它的contentSize和nativeContentSize,以及根据translatesAutoresizingMaskIntoConstraints = false接受的答案进行设置。

当父视图加载并设置容器视图时,每个UITableViewCells的固有高度被推断为0,因此,UITableViewDelegate方法为:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell

不会被调用。这使UITableView看起来好像没有内容。

覆盖固有内容大小以返回实际内容大小意味着表视图以其内容所需的大小显示。

埃米利奥·佩拉兹(EmilioPeláez)撰写的一篇很棒的文章更深入地探讨了这个话题。


1

我尝试了此解决方案并为我工作。
在destination(child)视图控制器中,尝试像这样访问父视图控制器:

if let parentVC = self.parent as? EmbededContinerViewController {               
   if let myParent = parentVC.parent as? ParentViewController {
      myParent.subViewHeight.constant += 2000
      myParent.subView.layoutIfNeeded()
   }

}

也许这不是正常的解决方案,但可以为我工作并解决我的问题。
我在Swift 5.1中尝试了这段代码。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.