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