背景
最近在做 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 這樣的值就可以實現新需求,十分方便。更重要的是,這樣的代碼往往是有意義的,所有的值和布局結果都是可以語義化表達的,這樣會讓整個代碼鮮活起來,充滿生命力。