UIScrollView添加AutoLayout约束的坑

作者: CoderAO | 来源:发表于2015-07-07 00:15 被阅读13715次

之前在使用AutoLayout给UIScrollView进行布局的时候,总会出现点这样那样莫名其妙的问题.我也曾跳坑两次,挣扎许久最后都以放弃storyboard改为代码实现而告终.今天终得正解,遂拿出来说说.

先从最基础的开始,我们试着在storyboard上添加一个UIScrollView,并且在内部添加一个和它一样大的UIImageView.

首先,拖一个UIScrollView到storyboard,设置约束如下:

顶部距离控制器view距离为50
左侧和右侧距离控制器view距离分别为0
高度固定250(多吉利的数字)
scrollView的约束

然后拖一个UIImageView到scrollView中,我们想让它在{0,0}处并和scrollView的尺寸一样,于是设置上下左右距离父控件都为0:

imageView相对scrollView的约束

好像没什么问题,可是...

约束报错了...

没看错,Xcode告诉我们这样安排约束是错误的.
UIScrollView的子控件添加约束与普通view不同,仅仅这4个约束不足以满足它的需求.

那么,怎样才是正确的做法呢?

首先:

scrollView自身的约束(scrollView的位置和尺寸)可以像正常的UIView一样参照其父控件添加.

正如上面我们第一步所做的,在给scrollView添加子控件之前,那四个约束决定了scrollView的大小和位置,这步是没有问题的.

问题的关键在于如何给scrollView内部的子控件添加约束.

scrollView内部子控件约束的添加需要遵循两个原则:

1、scrollView内部子控件的尺寸不能以scrollView的尺寸为参照
2、scrollView内部的子控件的约束必须完整

首先,子控件的尺寸不能以scrollView的尺寸为参照,那么我们有两种选择:

  • 提供一个具体值的约束(比如200)
  • 子控件的尺寸可以参照scrollView以外其它的控件的尺寸(如控制器的view的尺寸)

其次,约束"完整"的意思是说:子控件在水平及竖直方向上的约束要把scrollView"撑满".

也就是说,在水平方向上,我们需要设置:

  • 子控件左侧与父控件的距离
  • 子控件自身的宽度
  • 子控件右侧距父控件的距离.

竖直方向上也一样,要设置:

  • 子控件顶部距父控件的距离
  • 子控件的高度
  • 子控件底部距父控件的距离.
    如图:
scrollView子视图的约束条件图1 scrollView子视图的约束条件图2

两张图片中,所有红色线条的长度都要确定(黄线表示对齐),才能保证AutoLayout不会报错.

为什么scrollView如此隔路(隔路:特殊,与众不同)呢?

这是因为,scrollView需要根据添加在其内部的子控件的宽高及与四周的距离计算出它的contentSize.

举个栗子:
一个添加在scrollView内部的imageView的宽高为{80, 50}, imageView距离上左下右的距离分别为:100, 200, 300, 400,那么不需要用代码赋值contentSize,我们就可以打印出scrollView的contentSize为{680, 450}.
如图:

IB添加约束的原理

如果理解起来还是有困难,我们可以把scrollView的contentSize的范围想象成一块UIView(上图中的蓝色区域),暂且叫它container(实际是没有这个东西的).当我们在storyboard或xib中设置子控件与scrollView之间约束时,实际上设置的是子控件与container之间的约束.

也就是说,子控件的约束决定了container的尺寸(contentSize).
这就说明了为什么我们要在水平和竖直方向用约束"撑满".如果不撑满,container不知道它自己应该多大.

也正是因为container的尺寸由子控件的约束决定,所以子控件的尺寸不能再反过来参照container的尺寸.不然你等于我,我等于你,那到底是多少呢?如果你是Xcode你也会抓狂.(再次强调那个container不是真的,只是为了方便理解)

理论部分解释完毕,回到一开始的案例上.

imageView有了上下左右四个约束,还缺少宽高,我们再添加个固定宽高的约束(可以大一点,太小了看不到滚动效果),问题就可以解决了.

强调一下, 用代码给scrollView添加约束(包括使用Masonry的情况)是一样的.

填平一坑,心中大喜.掌握了这些,复杂一点的scrollView布局我们也不怕了.
给大家出个题目,如果是要在scrollView里面添加三张水平方向滚动的图片怎么搞? 参考答案:https://github.com/CoderAO/UIScrollViewAutoLayout

相关文章

网友评论

  • Ko_Neko:请教一下博主,如果是在ScrollView里添加2个tableView(水平)该如何设置呢?
    CoderAO:我知道回复得已经太晚了,这里还是回答一下.跟添加两个view的原理是一样的,两个tableView要有固定的宽度,两个tableView之间的距离也要有个固定的宽度,他们和scrollView上下左右的距离也要固定,这样基本上问题就不大
  • csr_yang:确实是坑
  • 47a6d15542bb:首先,子控件的尺寸不能以scrollView的尺寸为参照,那么我们有两种选择:

    提供一个具体值的约束(比如200)
    子控件的尺寸可以参照scrollView以外其它的控件的尺寸(如控制器的view的尺寸)
    -------------------------------
    “参照scrollView以外其它的控件的尺寸”——还真TM难办,因为ScrollView本身就已经是参照其他控件才确定它的位置和大小的,现在要让ScrollView里面的内容脱离ScrollView来确定大小,太鸡巴难了,要打乱布局重新设计才行。
  • 苏堤拂晓:你这样玩Autolayout太复杂了。用QuickVFL快多了。github上搜索QuickVFL
  • 高高叔叔:兄弟你写了这么多其实就一句话。
  • d053345b0b60:博主,问个问题,你的那个“在scrollView里面添加三张水平方向滚动的图片”的例子我已经从git上下载下来了,有个地方不懂怎么设置,就是怎么设置 :Image View1.centerY = Image View3.centerY ?像这样的约束怎么添加呢?
  • 哈么么茶:真心解决一个问题,之前看了没在意。后来添加scrollView发现乱动。
  • single_heart:困扰了好多天的问题得以解决,谢谢谢谢~
  • 98be6e2a35d7:楼主你好 按上图中的例子 测试的时候 图片中图片后来又补上 固定宽高的约束,就可以达到滚动效果 , 但是在不同的屏幕适配的时候, 图片宽高的约束已经写死了,那么会显示不同的效果~ ,,所以想问 要怎么保持适配
    CoderAO:@傅怪人超级爱洗澡呐 其实吧,我觉得scrollView里面用autoLayout就是一个坑,我自己是很少用这种了,发现调的时候很难受,还不如直接代码写.如果添加的内容比较复杂,就把里面的东西单独放到一个view里面再添加到scrollView上.
  • 小凡凡520:good mark
  • JohnHow:好文,写得十分清晰啊
  • 493f13b4f10b:请问如何做横向滚动呢?
    CoderAO:@zhaobo2014819 当你添加在scrollview内部的控件们水平方向的宽度以及加上各种间距超过scrollview本身的宽度,就可以水平滚动了
  • imbear:刚好遇到这个坑
  • Nlinger:同是程序媛,楷模姐姐哦,向你学习
  • 小生不怕:好文章
  • 光明程辉:哈哈!前2天使用我也遇到! :smile:
  • 44b811bc27de:表示已经跳过坑 来学习学习 博主好厉害 :+1:
  • 9bfe700d122a:我必须要顶一下博主,因为像这样细心讲心得的博主不多了。而且还很耐心的解答别人问的很简单的问题。挺你!!真大神
  • ttw076:挺好???
  • CoderAO:@8ab8a4bc7c3e 选中button 右侧属性查看器第二行有个state config选项,可以选择button的四种不同状态,每选中一个状态,设置下面的title textColor image等属性就是对应这个状态的
  • 8ab8a4bc7c3e:问个问题啊,xib上怎么给button设置不同状态图片呐
  • e9259107abfa:@CoderAO 嗯,好的
  • CoderAO:@yhoon 学习masonry主要看他demo里面的例子就掌握一大半了,有不懂的直接问我
  • e9259107abfa:最近在尝试用Masonry进行布局,也可以实现约束的效果,代码实现的,不过还没进一步研究,还需要学习好多 :flushed:
  • CoderAO:@斯卡 题目叫坑只是为了增加表达效果的
  • 斯卡:@CoderAO 亲测,果然不用,不过在布局复杂视图的时候我还是习惯用这种方法,至少目前没踩过坑
  • CoderAO:@斯卡 你说的那个创建一个真实的container其实是可以省略不用的
  • 斯卡:用代码写scrollview的约束时也需要加一个container,这里的container是真实的UIView的一个实例, container的大小是由子view的约束来计算的,然后container与scrollview再设置对齐.这样就能确定scrollview的contentSize大小了,与你这篇文章讲的差不多,这次算加深了印象 :stuck_out_tongue_winking_eye:
  • 350fee9655f0:拜读学习了……

本文标题:UIScrollView添加AutoLayout约束的坑

本文链接:https://www.haomeiwen.com/subject/ukbyqttx.html