autolayout

Iphone的尺寸在不断变化,ios7系统和之前的版本相比,在视图的frame上也发生了很大的变化,这使得适配工作也越来越繁琐。苹果也许也意识到了这点,在6中推出了新的布局方法auto layout来解决这个问题,不过使用这个布局确实方便很多。

我们都知道,layout之适用与6以上的系统。但根据最近一份苹果官方的调查报告显示,ios系统的ios6以上的占有率已经达到了90%以上,因此在以后的应用中,也可以直接支持6以上了。所以可以直接使用auto layout进行布局了。

以下将对autolayout进行简要介绍,并对常见的问题进行分析,并给出相应的解决方案。

 

一、ios7和ios6中,view坐标的变化

先来看一下ios7和之前版本在frame上的差别:(以下的高度等,都是在viewdidappear中打印出来的)

在有导航栏的情况下,,view的frame和bounds为:

屏幕大小

系统版本

7

6

3.5

Frame

(0,64,320,416)

(0,0,320,416)

bounds

(0,0,320,416)

(0,0,320,416)

4

Frame

(0,64,320,504)

(0,0,320,504)

bounds

(0,0,320,504)

(0,0,320,504)

 

在无导航栏或者导航栏隐藏的情况下,view的frame和bounds为:

屏幕大小

系统版本

7

6

3.5

Frame

(0,0,320,480)

(0,0,320,460)

bounds

(0,0,320,480)

(0,0,320,460)

4

Frame

(0,0,320,568)

(0,0,320, 548)

bounds

(0,0,320,568)

(0,0,320,548)

 

注:frame是相对父视图,bounds是相对自己的

在viewdidload中打印出来的结果,与xib中设置的视图高度是一致,即使将view的高度设置成freeform,打印出来的结果也不会有变化。

 

从以上有导航栏和无导航栏的情况对比可以得出结论:

1、        在不使用autolayout进行布局的情况下,使用系统的导航栏(在5之后,导航栏就有了很多可以自定义的功能,基本能满足UI的要求),而不是自定义的,并且在进行子视图的添加时,使用self.view.bounds来获取高度或者原点位置,对于简单布局,就能解决适配的问题了。

例如,要将uiimageview放在view的(0,0)坐标位置,大小和view一样大,那么可以这样写:

 

UIImageView *imgView = [[UIImageViewalloc]initWithFrame:self.view.bounds];

[self.viewaddSubview:imgView];

 

2、        在没有导航栏或者自定义导航栏的情况下,就得定义出状态栏的高度,然后在代码中,通过判断系统的版本,将子视图的高度和位置进行调整,以适应不同的版本。

 

UIImageView *imgView = [[UIImageViewalloc]init];

    if(OS_VERSION >= 7.0)

    {

        imgView.frame = CGRectMake(0,STATUSBAR_HEIGHT,CGRectGetWidth(self.view.bounds) , CGRectGetHeight(self.view.bounds)-STATUSBAR_HEIGHT);

    }else{

        imgView.frame = self.view.bounds;

}

[self.viewaddSubview:imgView];

或者直接通过获取屏幕的大小进行计算。

但添加的代码最好是在viewdidappear中进行计算,如果是通过xib进行布局的,可在viewdidappear中对子视图的坐标进行调整。因为在viewdidload中获取到的视图的frame和bounds,与xib中设置的视图高度一致,在不同屏幕中显示的值是一样的,因此不具有参考价值。

         通过以上bounds和frame的对比,目前也有一种比较常用的适配方式,就是将bounds的y值上移20个像素(即状态栏的高度)。

总之,不管用什么方法进行实现,都不可避免的要进行系统版本的判断,并且在布局较为复杂的情况下,也要根据屏幕大小或者系统版本进行高度或坐标的调整。

还有一种情况,在tableviewcell中,label都是需要自适应高度的,而在ios7中,计算label高度的方法变化了,因此又得判断系统版本。

在支持屏幕旋转的情况下,适配就更为头疼了。

         基于使用以往方法进行适配之麻烦,所以使用auto layout进行布局,系统版本支持6以上。

 

二、auto layout

使用自动布局,不仅可以很容易的支持不同大小的屏幕,一个额外的功能,它也使得本地化几乎变得微不足道。

通过auto layout,来对视图添加约束,实现自动布局。常用的设置有left, right, top, bottom, leading, trailing, width, height, centerX, centerY, andbaseline。另外,约束条件至少有两个,如果过少,会出现警告并导致布局达不到想要的效果;如果过多,最坏会导致应用crash。基本语法如下:

V:  :表示垂直方向

H:  :表示水平方向

|: 表示父视图

-:表示距离

>= :表示视图间距、宽度和高度必须大于或等于某个值

<= :表示视图间距、宽度和高度必须小宇或等于某个值

== :表示视图间距、宽度或者高度必须等于某个值

@  :优先级设置, 最大为  1000(通过xib添加的约束,默认优先级为1000)


1.V:|-10-[view]-50-|:  视图相对于父视图的距离为:上边距为10,下边距为50

2.H:|-10-[view]-50-|:  视图相对于父视图的距离为:左边距为10,右边距为50

3.V:|-10-[view]:  视图相对于父视图的距离为:上边距为10

4.H:[view]-50-|:  视图相对于父视图的距离为:右边距为50

5. V:[view(50.0)] : 视图高度为  50

6. H:[view(50.0)] : 视图宽为  50

7. H:[view1(50.0)]-80-[view2(view1)] : view1视图宽为 50,view1view2的水平间距为80,且view2的宽度和view1相等

9: V:|-(==padding)-[imageView]->=0-[button]-(==padding)-| : 表示离父视图的距离

Padding,这两个视图间距必须大于或等于0并且距离底部父视图为 padding

10:  H[wideView(>=10,<=700)]  :视图的宽度为至少为10,最大为700

11:  H[wideView(100@20)]  :视图的宽度为100,且优先级为20


1、        xib实现

在xcode的xib中,你可以很方便的对各种控件进行添加约束,来实现布局。在xocde的菜单栏中可以找到设置项,如下图所示。

在xib中,这个也可以实现相同的功能。

auto layout可以理解为是一种相对布局,因此在添加约束时,至少要选中两个视图。Pin中的所有选项,是相对父视图而言的,可以只选中一个视图进行设置。

在xib中添加了约束后,若约束添加的有问题,xib也会自动检测并提示出错的地方,如下图所示:


可以使用Editor中的Resolve Auto Layout Issues进行解决,不过是系统根据你视图摆放的位置进行添加的,有可能不对。如图所示。


2、        代码实现

在UI很复杂的情况下,使用xib布局会显的很麻烦,并且调试起来也很困难。因此可以使用代码进行实现。针对自动布局,苹果推出了一种Visual FormatLanguage.详细文档可参见苹果官方文档:

https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/AutolayoutPG/VisualFormatLanguage/VisualFormatLanguage.html。

注:将translatesAutoresizingMaskIntoConstraints属性设置为NO。默认值为YES,通过此属性值来判断是否使用autolayout进行布局。若没有设置此属性,Log中会输出错误。

3、        xib和代码结合

如果只是简单的UI布局,用xib会很快捷。可根据实际情况进行对比选择。若使用xib创建了一些view,但没有添加约束,那么系统会自动添加一些约束,且这些约束的优先级为1000,即最高优先级,所以如果之后需要使用代码对这些view进行布局,那么在写布局代码前,需将系统添加的约束remove掉,否则会crash。

4、        label高度的计算

使用autolayout进行布局后,对于cell的高度的计算,使用

[self.sizingCell.contentViewsystemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height,这样就能计算出cell的高度了,而不再需要进行手动计算了。

对于label的高度计算,需要设置preferredMaxLayoutWidth属性,否则将不能计算出label的正确高度。

5、        scrollview

6、        例子

(scrollview和相关例子将在下一篇博客中继续)

你可能感兴趣的:(iOS)