【问题标题】:Sizing a Container View with a controller of dynamic size inside a scrollview在滚动视图中使用动态大小的控制器调整容器视图的大小
【发布时间】:2016-05-03 01:07:34
【问题描述】:

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

View Controller A 是滚动视图,其中包含容器视图,以及下面的更多内容。

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

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

如果视图控制器 B 的高度也为 250,这将是预期的输出。它也适用于高度 1000,据我所知,所有自动布局约束都已正确设置。不幸的是,由于高度实际上应该是动态的,所以我想完全避免设置高度约束。

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

有没有什么办法可以在不设置高度限制的情况下,根据 View Controller B 的大小来调整 A 中的 Container View 的大小?

【问题讨论】:

  • 您可以将高度约束设置为 IBOutlet 并在代码中动态调整它们
  • 这是我最接近解决方案的方法,但这是最简单的方法吗?我希望有一些我错过的东西可以比手动设置高度限制更容易解决问题。
  • 我认为您也可以在这里使用 preferredContentSize - 只需不断更改它,你知道吗?

标签: ios uiscrollview autolayout uicontainerview


【解决方案1】:

我尝试了这个解决方案并为我工作。
在目标(子)视图控制器中尝试像这样访问父视图控制器:

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

}

也许这不是正常的解决方案,但对我有用并解决了我的问题。
我在 Swift 5.1 中尝试过这段代码。

【讨论】:

    【解决方案2】:

    基于@Mischa 对这个问题的出色解决方案,如果容器嵌入了一个动态大小的 UITableView,那么您需要考虑覆盖它的 contentSize 和 intrinsicContentSize,并根据接受的答案设置 translatesAutoresizingMaskIntoConstraints = false

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

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

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

    覆盖内在内容大小以返回实际内容大小意味着 tableview 以其内容所需的大小显示。

    Emilio Peláez 的 article 对此主题进行了更深入的探讨。

    【讨论】:

      【解决方案3】:

      Swift 4、Xcode 9

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

      我的层次结构:ScrollView --> Content View (UIView) --> Views |集装箱视图 |其他视图。

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

      1. ScrollView:Top、Bottom、Leading、Trailing to Superview(安全区域)
      2. 内容视图:顶部、底部、前导、尾随、与 ScrollView 等宽,但也具有等高(优先级较低的约束:250)
      3. 视图:正常的自动布局约束。
      4. 容器视图:顶部、底部到相邻视图、前导和尾随到安全区域。
      5. Container View 的嵌入式 VC:所有约束都垂直连接,底部约束设置为较低的优先级,但大于 Content View 的 Equal Height one!在这种情况下,500 的优先级起到了作用。
      6. 如其他答案所述,将 view.translatesAutoresizingMaskIntoConstraints = false 设置为 prepareForSegue()loadView()

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

      【讨论】:

      • 嗨 Teodor,我阅读了您的回答,我认为您可以帮我解决问题:stackoverflow.com/questions/48797508/twitter-profile-effect 谢谢您的帮助。
      • 任何 GitHub 示例?
      • ContainerView中有滚动视图时不工作
      • 如果可以的话,我会投票 5 次。这个循序渐进的答案很简单,可以解决 3 小时的 IB 限制问题。
      • 惊人的解决方案!!!为我工作。但我现在看到另一个问题。我的嵌入式表格视图控制器就地滚动,但是滚动视图已停止滚动
      【解决方案4】:

      根据@Mischa 的回答,我能够根据容器视图的内容动态调整高度:

      在containerView的viewController中写:

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

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

      在我的例子中,我试图将容器的大小调整为 viewController 中的 tableView。因为 tableView 有一个灵活的高度取决于它的 superview(所以对 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,这确实是一个很棒的提示。干杯
      【解决方案5】:

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

      您所要做的就是告诉系统它不应该添加模仿在 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,界面生成器就知道要打破哪个约束。然而,在运行时——当 translatesAutoresizingMaskIntoConstraints 属性按上述设置时——你的根视图不再有固定的框架,系统将使用你的 999 优先级约束。

      【讨论】:

      • 这很好用,谢谢!滚动视图在编辑器中有一些约束问题,但如果我在构建时删除的容器上设置高度约束,这些问题就解决了。
      • 如果您在 Interface Builder 中转到 Size Inspector,向下滚动并从 内在内容大小 下拉菜单。然后,您可以为容器视图设置一个固定的内在大小,该大小仅由 Interface Builder 用于布局视图,但不会在运行时应用。
      • 在 iOS 9 上工作,我发现在 PARENT 视图控制器(而不是子容器 VC)中设置 translatesAutoresizingMaskIntoConstraints = NO 可以解决问题。我将我的底部约束优先级保持在 1000,这允许整个容器视图增长。否则,容器视图的内容超出了我的容器视图的底部,我在布局中看到了其他奇怪的东西。感谢您解决这个问题!!!
      • 这对我不起作用,正在使用容器视图的 iboutlet 并调整高度工作
      • 伟大的帮助!非常感谢!
      猜你喜欢
      • 2012-06-29
      • 1970-01-01
      • 2015-06-13
      • 2019-04-13
      • 1970-01-01
      • 2021-05-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多