背景
最近在做 iPhone4 和 iPhone6 及 iPhone6 plus 的适配工作。由于历史原因没有用 AutoLayout ,也由于历史原因老代码的布局全是用数字一个一个写死的。这就给适配带来了莫大的困难。比如下面这段代码:
UILabel *infoLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 241, 320, 28)];
...
0这种数字还好说,241就完全让人摸不着头脑,至于320这个改成屏幕宽度倒也就还好,但是28这种神奇数字又是什么呢。这种代码虽然写起来容易,但是维护困难,可读性极差,尤其是有多个控件布局的时候,依赖关系不明显,如果调整布局需要挨个重新计算并设置值,极难维护。
集大成者莫过于此:
CGRect rect = CGRectMake(12.2+(page-1)*320+42.5*(i%7),((totalRows-1)%3)*55+2,42.5,42.5);
屏幕适配的分享今天早上看到这代码差点就抱着键盘哭了出来。
下面和大家聊一聊屏幕适配中需要注意的内容。
大前提是:纯粹通过代码设置坐标和大小的布局方案(我觉得还是 xib + autolayout 的组合适配起来更轻松一点)。
合理设计
布局虽说是个体力活,但同时也是个艺术活。之所以称之为设计,是因为同样的设计稿可能有很多种实现方式。UIKit 提供了很多现成可用的控件,如何充分利用这些控件实现自己的布局结果就是一个需要思考的过程了。
举个简单的例子,一个滑动挂断电话的按钮,你可以通过 UIImageView 实现,添加按下的监听然后跟随手指移动,松手之后再动画回到原地即可。你也可以用 UIScrollView 实现,设置 ContentSize 宽于屏幕,从而控制滑块范围。当然你也可以用 UISlider 实现,只需要设置滑块的图像即可。各有优劣,自行判断。
数据语义
如果我想让宽度为100的按钮位于屏幕三分之一处,我可以设置它的 x 值为 57 轻松完成任务。这样虽然简单,但是过段时间再回来维护代码的时候会对这样的神奇数字不知所措,如果要调整布局更是举步维艰。我觉得比较好的方法是把数据由来列出来,像这样:
float x = kScreenWidth / 3 - btnWidth / 2;
这样看起来就轻松多了:屏幕的三分之一处再往左半个宽度,也就是 x 的值。
相对布局
我们常常遇到很多控件同时出现的情况,比如三个从上往下依次间隔10像素的按钮,可以这样实现:
CGRect rect1 = CGRectMake(0,0,100,44);
CGRect rect2 = CGRectMake(0,54,100,44);
CGRect rect3 = CGRectMake(0,108,100,44);
但是如果我们想把这三个按钮同时下移,那我们就需要挨个设置一遍。比较好的方案是通过相对布局来实现。
CGRect rect1 = CGRectMake(0,0,100,44);
CGRect rect2 = CGRectMake(0,rect1.origin.y+rect1.size.height,100,44);
CGRect rect3 = CGRectMake(0,rect2.origin.y+rect2.size.height,100,44);
当然什么场景使用相对布局,针对哪些控件使用相对布局,这些就是我们需要设计的问题了。
层次关系
一般情况下,一个页面内会出现很多控件,如果都通过 addSubview 添加到视图中很容易混乱。可以通过一些 UIView 作为容器辅助布局。个人觉得可以给控件们安排好深度,同个深度的控件再进行分组,有助于管理。
灵活精准
布局代码的灵活性十分重要。比如两个和屏幕等宽的按钮,如果通过160设置宽度,现在iPhone6一出之后就纷纷中枪了。再比如那种 CollectionView 的单元格宽度高度写死了44.5的,最好是通过计算动态获取。虽然有一定的计算量,但是在后期如果遇到设计变更什么的,只需要改个宏定义的 CELLS_PER_ROW 这样的值就可以实现新需求,十分方便。更重要的是,这样的代码往往是有意义的,所有的值和布局结果都是可以语义化表达的,这样会让整个代码鲜活起来,充满生命力。