1. 文檔綜述
自iphone6/6+發布,ios屏幕分辨率的種類一下從2種變成了四種。對於以前很多手寫UI,並且使用絕對坐標的UI,可能會發生異變,本文主要介紹在純手寫UI條件下,ios應用界面適配的一些經驗了。
2. iphone分辨率px, pt與ppi,以及@3x
老生常談的一個問題了。但是隨着iphone6+的引入,局面有了新的變化。首先介紹一張表,本章后續內容圍繞此表展開:
手機 |
pt |
px |
ppi |
iphone4/4s/ |
320x480 |
640x960 |
326 |
iphone5/5c/5s |
320x568 |
640x1136 |
326 |
iphone6 |
375x667 |
750x1334 |
326 |
iphone6+ |
414x736 |
1242x2208 (1080x1920) |
401 |
對於6+之前的手機,pt和px的比例為1:2。而6+出來之后,這一比例達到了1:3。同時分辨率達到了1242x2208(使用ip6+截圖,再傳到電腦上看,就是這個分辨率),而iphone實際分辨率為1080x1920。分辨率的比率為1.15:1。
對於ppi,6+之前均為326,而6+之后變為401。
2.1. 素材資源發生的變化@3x
在實際開發中,素材通常是UI美眉負責提供。從@2x到@3x,素材的分辨率提高了1.5倍。例如一個@2x的素材大小為44x44,那么相應的@3x大小分辨率為66x66。
文件命名的方式依然沒變:${IMG_NAME}@3x.png這種形式了。命名好的文件丟入資源文件夾內,只要代碼保持一致,文件名稱不變即可。
2.2. UI到代碼
由於ip6+點(point)和像素(pixel)的關系為1:3,因此,當UI設計稿基於1242x2208分辨率【iphone6+】圖給定UI設計稿時,程序員進行實際換算為設計稿的1/3。
假設上圖是一個設計稿,基於1242x2208。UI美眉給了兩個按鈕間距為30px。為了實現以上效果,則可以在代碼中寫:
btn2.frame = CGRectMake( GetX(btn1.frame)+GetWidth(btn1.frame)+30.f/3,
GetY(btn1.frame),
GetWidth(btn1.frame),
GetHeight(btn1.frame)
);
由於實際間距為30px,因此在代碼中應該做除3的處理,保證間距效果。當然,如果設計搞給的不是ip6+的圖,那么這里的30.f/3還是應該按照以前的老規矩:30.f/2。
2.3. 代碼到UI
從UI到代碼,只要在明確UI給出的設計圖是基於哪部手機(具體來說是哪種分辨率)即可。但是,對於已經寫好的代碼,在不同的UI上表現是否相同呢?還是給出類似上面的代碼:
btn2.frame = CGRectMake( GetX(btn1.frame)+GetWidth(btn1.frame)+10.f,
GetY(btn1.frame),
GetWidth(btn1.frame),
GetHeight(btn1.frame)
);
有兩個btn,btn1和btn2之間的水平間距是10。現在問題來了:這兩個btn之間的距離在不同手機上看起來是相同的么?我們進行實際的換算:
手機 |
pt |
px |
iphone4/4s/5/5c/5s |
10 |
20px |
iphone6 |
10 |
20px |
iphone6+ |
10 |
30px |
因此,相同的代碼,在iphone6+和非iphone6+(ip4, 5, 6)的手機上表現是不同的:
在非iphone6+中,間距為20px;在iphone6+中,間距為30px。糟了,那間距在不同手機上相差了10個像素?外觀就有差距了,如何調整?
【其實不用太過擔心】,他們的間距【看起來】依舊相同。還是給出一個表格:
手機 |
pt |
px |
ppi |
iphone4/4s/5/5c/5s/6 |
10 |
20 |
326 |
iphone6+ |
10 |
30 |
401 |
繼續回顧以前的討論:
·分辨率縮放
ip6+的實際分辨率為1080x1920,和1242x2208的分辨率的比例為1:1.15。那么30px在實際距離變為了:
可以看到差不多在26個px左右,間距【看起來】變小了一些。
·ppi影響
ppi,每英寸像素個數。ip6+的ppi為401,而非ip6+的ppi為326。相同屏幕物理距離,ip6+會顯示更多的像素;或者,相同px長度,在ip6+上【看起來】更短。它們之間的比例:
·【看起來】
現在我們計算30個px在ip6+上與以前ip手機相比【看起來】有多長:
換算完畢之后,pt為10,在ip6和ip6+上面的間距【看起來】變成了:
20px和21.2px在高分屏上,並且是用肉眼觀察,它們的區別是很不明顯的。那么結論就是,相同的UI代碼,在不同的手機上的表現是基本相同的。對於在以前手機上寫死的相對距離,不用過於擔心在ip6+上的排序會亂掉。
從ip6+的處理上可以看出,蘋果手機在設計時對開發者的關懷。
3. 適配心得
總結自己對ip6、ip6+的適配心得,未來有更多經驗后,會繼續豐富本章中的內容。
適配問題其實在ip5出現的時候就存在了,喬布斯的3.5寸是最方便單手操作的尺寸已經成為過去,ip5的4寸屏幕扇了自己的臉。隨着ip6的出現,屏幕分辨率也越來越多樣化,以前在iOS中很方便的寫死坐標法將越來越不好用了。因此需要進行適配。
可以對控件間距進行適配,也可以對控件大小本身適配。
3.1. 適配原因
適配的最主要原因就是以前潛在的代碼存在手寫死坐標,導致在屏幕高度和寬度都發生變化后帶來的UI錯亂問題,簡單舉兩個例子:
·例子1
某人想把一個按鈕放在屏幕右邊的位置,寫下了如下代碼:
btn.frame = CGReactMake(290,y,width,height);
這段代碼在ip4/5上面都正常,因為屏幕寬度均為320,而對於ip6/6+,屏幕變寬了,按鈕位置看起來發生了變化:
如上圖,按鈕在ip6,ip6+上面表現的不再靠屏幕右邊,而是越來越靠左。
·例子2
對於兩個按鈕的間距或者按鈕寬高度問題,前面已經討論過了,在不同的屏幕上【看起來】是一樣的。但是屏幕大小發生了改變,因此也需要酌情進行適配。酌情的原因是,有些間距UI要求就是固定間距,而有些間距UI要求是相對間距,所有要根據情況來看。
現在給一個例子,依舊是前面的間距問題:
btn2.frame = CGRectMake( GetX(btn1.frame)+GetWidth(btn1.frame)+10.f,
GetY(btn1.frame),
GetWidth(btn1.frame),
GetHeight(btn1.frame)
);
在iphone4/5時,btn2在間距btn1右側10單位后,來到了比較靠近的屏幕右側的位置。而當屏幕變寬之后,在ip6和ip6+上面卻無法達到靠近右側的效果。
3.2. 常見適配方法
適配的總體原則就是相對布局了。
后續幾個小節介紹一些常見的適配方法。未來總結出更多新的適配思想后,也會對文章內容進行響應補充。
3.2.1. 不適配
對於ip6或者6+最簡單的適配方法就是:不適配。
曾經ip5剛剛出現的時候,以前基於ip4寫的應用在ip5上運行的話,會發現屏幕的頂端和底端出現兩條黑又粗的黑邊。出現黑邊的主要問題是ip4和ip5的屏幕比例不同:
而當ip6,6+出現時,屏幕的比例變成了:
從上面計算可以看出,ip5,6,6+的屏幕比例均為16:9。因此,當一個app【支持ip5】的話,那么在ip6/6+上運行時,系統將會對畫面進行拉伸,以便填充整個屏幕。
拉伸之后看起來圖標、字體、圖片什么的都變大了,並且清晰度降低了,感覺就是在PC上全屏運行FC模擬器玩游戲這種感受。雖然降低了用戶體驗,但是比以前屏幕頂端和底端出現粗又黑的黑條來說,簡直是好多了。
3.2.2. 占屏比適配
以前UI給距離,長度等內容,通常給定的是像素值px。現在為了進行適配可以給出像素值相對某個長度的比例:
例如,兩個按鈕的距離是屏幕寬度的12%。
對於不同手機,屏幕寬度是不同的。這樣兩個按鈕的間距在不同屏幕上就顯示合適了。使用[UIScreen mainScreen].bounds.size.width求出屏幕寬度。
當然也不一定使用屏幕寬度作為基准尺度,在實際應用中,還可以選擇superView frame的寬度、按鈕本身寬度、某個基准圖片的寬度等作為基准尺度。
3.2.3. 比例縮放適配
另一種適配方法就是比例縮放適配了,根據屏幕比例進行適配。例如,在ip5上,btn1,btn2的橫向間距為10:
那么,在ip6/6+的間距可以根據屏幕長度帶來的變化進行:
比例縮放適配,使得UI僅關注某個iphone機型,其它機型根據屏幕寬度和高度進行縮放即可。