iOS 实现在 Xib 中 UIScrollView 根据 subview 动态变化大小

需求

最近碰到产品提出这样一个需求:在父视图A当中,需要展示一个子视图B。视图 B 宽度固定,高度随视图 B 中的内容多少而变化。而视图 A 也会随着 B 视图的高度变高而变高。不过视图 A 最高不能超出当前控制器视图的下边界,如果内容过多,则需要支持 Y 方向滚动。

效果图如下


iOS 实现在 Xib 中 UIScrollView 根据 subview 动态变化大小_第1张图片
文字比较短的时候,不支持滚动

文字如果过长,需要支持滚动

大家可以思考一下,如果是你,在 Xib 中如何实现这个需求?

分析

  1. 很显然,在上面所提出的需求中,视图 A 需要支持滚动,所以 A 必须是 UIScrollView 的子类。
  2. 和平常需求有所不同的地方是,UIScrollView 的高度是不固定的,需要由子视图 B 的高度和自己的最大高度限制共同决定。

重温在 Xib 中如何设置 UIScrollView 约束

  1. 如果父视图是 UIView 子类,设置了 x 方向和 y 方向分别2个约束,子视图同样也设置了 x 方向和 y 方向分别2个约束,在 xib 中是一切正常,不会报错的。
  2. 可如果父视图是 UIScrollView 类,做了与 1 中同样的约束的话,则会报错误,如图
    iOS 实现在 Xib 中 UIScrollView 根据 subview 动态变化大小_第2张图片
    报错提示图
  3. 点击图上的叹号,我们可以看看官方的解释
    iOS 实现在 Xib 中 UIScrollView 根据 subview 动态变化大小_第3张图片
    官方说明
  4. 上图说明大致上说了,还需要 UIScrollCView 的 subview 添加额外的两个x、y方向上的约束,这样子 Autolayout 才能计算出 UIScrollView 的 contentSize,然后确定可滚动区域。
  5. 而像普通的 UIView,由于没有滚动区域,size 和 contentSize 是一样的,所以在1中那样设置是不会报错的。
  6. 从上面的分析,我们可以知道,我们只能通过 subview 来确定 UIScrollView 的 contentSize,而不能确定 UIScrollView 的 size。难道我们必须在代码中实现 UIScrollView大小的动态变化吗?No No No,接下来就给出解决方案。

解决方案

  1. 在当前视图中,引入一个透明视图 UIView c,作为我们曲线救国的标尺view。我们可以将这个 c 放在与 UIScrollView 同层级上。
  2. 设置 c 的 height 约束与 UIScrollView 下子视图 b 的 height 约束相等,并任意设置其它约束。保证约束不报错。
  3. 设置 c 的 height 约束与 UIScrollView 的 height 约束相等。
  4. 重新设置 UIScrollView bottom 约束,将 UIScrollView 的 bottom 约束设置 为与 其 superview 的 bottom 相同,并将 Relation 大小关系设置为 UIScrollView 的 bottom 小于等于Less Than or Equal superview bottom。这项约束的优先级必须高于第三步中设置的约束。简单做法是我们可以将第3步设置的约束优先级下调为999。

总结

在这个约束设置中,最重要的2点

  1. 首先是通过标尺 View 作为中间人,来决定 UIScrollView 的大小。
  2. UIScrollView 需要设置优先级较低的控制 size 变化的约束,其次需要设置一个优先级较高的,控制 size 最大值的约束。

过两天我会放出 demo,有什么不明白的,或者有更好解决办法,都欢迎和我讨论,谢谢大家。

你可能感兴趣的:(iOS 实现在 Xib 中 UIScrollView 根据 subview 动态变化大小)