首页 > 代码库 > 在UIScrollView中使用Autolayout布局

在UIScrollView中使用Autolayout布局

之前翻译过一篇《如何在AutoLayout 中使用UIScrollView (多个ContentView)》(以下简称《如何》)。在这篇文章中很详细地解释了在UIScrollView中使用自动布局的种种限制和注意事项。

我本来以为这已经解释得很清楚了。但是仍然有读者说文中示例虽然可行,但在其他界面上却无法做出同样的效果。

考虑到也许是文中例子过于复杂,使得有的读者看虽然看得懂,照着文中步骤也能做出效果,但由于没有真正理解文中的原意,一旦离开例子实现自己的UI就犯难了。

我们另外举一个简单例子,以此来充分理解UIScrollView在Autolayout下使用的基本原则。

《说明》一文中列举了很多原则,但最根本的其实只有以下两条:

 

原则1:UIScrollView的size依赖于subviews

 

首先在画布中拖入一个UIScrollView。用Pin按钮,随意设置其布局。甚至不用设置。

 

因为《如何》一文中的第一个原则是:UIScrollView的布局依赖于subviews。因此我们设置UIScrollView的布局约束是没有用的。我们只需要将subviews的size都明确下来,这条原则自然不成问题。

 

UIScrollView的size(即contentSize)则根据subviews所占据的size来计算。当然,如果contentSize的内容不足以布满整个UIScrollView时,滚动条将不会出现,UIScrollView也不会滚动。

 

原则2:subviews的size不能依赖于UIScrollView

 

比如你设计这样一个布局:

 

UIScrollView包含两个subview:UILabel和UITextField。

 

UILabel的Pin约束设置如下:


注意,这里我们固定了UILabel的宽度为100,而Label的高度也是固定的(lines设置为1)。这是可行的,因为它的宽高都没有依赖于UIScrollView了。

但我们不可能所有控件都使用固定的宽高,那样就不叫做“自动布局了”。

例如,UITextField,我们准备设置它的Pin约束为:


这样,UITextField没有固定的宽高了。这样说也不对,其实UITextField是有固定高的,对于一个使用了默认边框类型(圆角)的UITextField来说,它的高度固定为30。但对于宽度则是由左边缘和右边缘决定。

从上图可知,它的左边缘距离左边的UILabel 8个像素,右边缘距superview的右边缘14个像素。这样UITextField的宽度应该由右边缘的x减左边缘的x得到。

由于左边的UILabel为固定宽度,所以UITextField的左边缘位置也是固定的。但右边缘的x则是相对于superview而定的,这就不可能固定。

我们知道在Xcode6的自适应布局上,view的大小实际上是根据设备而变的,在iPhone上是一个size,在iPad上又是另一个size。

但无论如何,我们的UITextField无论在何种设备上都能自适应。无非是在iPhone上略显窄一点,在iPad上则宽一些。

 

但是当你设置这样的约束后,你会发现出现了红色的布局警告:



这表示UITextField的宽度在运行时会比布局时短的多。运行效果如下:


这根本不是我们想要的样子。

这是因为UITextField违反了原则2:subviews的size不能依赖于UIScrollView。

如上所述,UITextField的宽度取决于superview的宽度。但和你理解的不同,UITextField的superview是UIScrollView而不是ViewController的view。

 

为什么subviews 的size不能依赖于UIScrollView?

很简单,因为原则1:UIScrollView的size依赖于subviews。如果subviews的size再依赖于UIScrollView,则布局引擎就混乱了。就像我们解一个方程式,x的求解要先知道y的值,而y的值却要先明确x的值,这个就无解了。

 

要解决这个问题,我们需要把UITextField的宽度明确,起码不能和靠不住的UIScrollView的size相关。我们可以这样设置UITextField的宽度约束:

找到UITextField的size面板,双击Tailing Space to这条约束(如果单击则仅仅是卸载而不是删除):


然后按delete键。

 

右键,从UITextField拖到ViewController的view,然后选择Equals Widths。然后双击新建的这条约束,修改为如下样子:


注意First Item和Second Item项,不要将二者搞反了。

 

运行程序:

 

iPhone和iPad上UITextField都能很好地适应。


对于高度的布局显示也是一样的,笔者就不一一举例了。总之,不得违反上述原则。

 


在UIScrollView中使用Autolayout布局