iOS 如何適應 iPhone 5s/6/6 Plus 三種屏幕的尺寸?

初代 iPhone

2007 年,初代 iPhone 發佈,屏幕的寬高是 320 x 480 像素。下文也是按照寬度,高度的順序排列。這個分辨率一直到 iPhone 3GS 也保持不變。


那時編寫 iOS 的 App(應用程序),只支持絕對定位。比如一個按鈕(x, y, width, height) = (20, 30, 40, 50),就表示它的寬度是 40 像素,高度是 50 像素,放在(20, 20)像素的位置。

iPhone 4

2010 年,iPhone 4 發佈,率先採用 Retina 顯示屏,在屏幕的物理尺寸不變的情況下,像素成倍增加,達到 640 x 960 像素。


這樣就出現一個問題,怎麼讓原有的 App 運行在新的手機上面?iPhone 手機一個優勢,就是有衆多優秀的 App,假如不兼容原有的 App,就相當於放棄這個得來不易的優勢,是很不明智的。


每當 iPhone 的屏幕有所變化,比如 iPhone 3GS 過渡到 iPhone 4, iPhone 4 過渡到 iPhone 5, iPhone 5 過渡到 iPhone 6,蘋果公司都需要想辦法來解決上述的兼容問題。


爲了運行之前的 App,引入一個新的概念 point(點)。點這個概念在 iOS 開發中十分重要,而實際用戶很少關注。iPhone 4 屏幕尺寸繼續保持 320 x 480,不過單位並非是像素,而是點。


  • 在 iPhone 3GS 中,1 個點等於 1 個像素。也就是說,點跟像素可以直接互換。

  • 在 iPhone 4 中,1 個點等於 2 個像素。


這篇文章中,我將點和像素當成一維的長度單位,而非二維的面積單位,這樣對於我來說更自然些,因此 1 個點等於 2 個像素。別的文章中可能會說 1 個點等於 4 個像素,其實是指 1 個點佔據了 4 個像素的面積,這樣也沒有說錯,注意上下文語境。


iPhone 4 和 iPhone 3GS 的屏幕尺寸實際上是一樣的,都是 3.5 英寸。同樣一個點,實際尺寸看起來是一樣的。只是 iPhone 4 在單位英寸上像素更多,看起來更細膩。


開發 iOS 的時候,使用點作爲基本單位會更加方便,列表對比:

這裏的屏幕模式可以初步理解成,一個點等於多少個像素。2x,就是 1 個點等於 2 個像素。


總結一下單位

  • 手機屏幕的物理長度,使用英寸作爲單位。比如 iPhone 4 屏幕是 3.5 英寸,iPhone 5 是 4 英寸,iphone 6 是 4.7 英寸,這裏的數字是指手機屏幕對角線的物理長度。

  • 屏幕像素,比如 iPhone 3GS 屏幕是 320 x 480 像素,iPhone 4 是 640 x 960 像素,這裏的像素可以想象成屏幕上真正用來顯示顏色的發光小點。

  • 點,開發 App 時候使用的單位,是一個虛擬的單位,並非實際存在的,因此點有時也叫虛擬點。點這個單位,用於屏蔽各個屏幕設備的不同,兼容以前的程序。


每英寸有多少個像素,稱爲 ppi(pixel per inch)。iPhone 4 的屏幕是 640 x 960 像素,3.5 英寸,我們沒有寬高的實際尺寸,就按照對角線來粗略計算它的 ppi。將像素當做長度單位,根據勾股定理,對角線就是 1154 像素。屏幕對角線的實際長度爲 3.5 英寸,也就是 1154 像素除以 3.5 英寸,得出 330ppi。而官方給出的數字是 326ppi。當像素太密,超過 300ppi 的時候,人眼也就不能區分出每個像素。因此 iPhone 4 的屏幕叫作 Retina 顯示屏。Retina 在英文中,是視網膜的意思。


iPhone 4 之後(x, y, width, height) = (20, 30, 40, 50),就表示高度爲 40 個點,寬度爲 50 個點,放在(20, 20)個點的位置。這種處理方法,將之前以像素作爲單位自動轉換成以點作爲單位,使得 iPhone 3GS 的應用程序,不用修改也可運行在 iPhone 4 上面。


文字,顏色等是矢量數據,放大不會失真。原有的 iPhone 3GS 程序,在 iPhone 4 上面運行,文字顯示也十分清晰。


而圖片並非矢量數據,處理方式有所不同。假設圖片 example.png,大小爲 30 x 40 像素(這裏的單位是像素,數字圖片的單位通常都爲像素)。當這張 example.png 在 iPhone 3GS 和 iPhone 4 中使用時候,都佔據屏幕上 30 x 40 個點。而因爲 iPhone 4 中 1 個點等於 2 個像素,也就是 30 x 40 像素的圖片,佔據了 60 x 80 像素的屏幕,因此這圖片在 iPhone 4 中看起來就會模糊。


開發的時候,爲使得圖片清晰,需要進行圖片適配。這時需要準備兩張內容相同的圖片,放在同一目錄下。


example.png // 30 x 40 像素

[email protected] // 60 x 80 像素


當程序中使用 example.png 的時候,會根據屏幕模式自動選擇對應的圖片。屏幕 1x 模式,就會選擇 example.png, 2x 模式就會優先選擇 [email protected],假如 [email protected] 不存在,就選擇example.png。


圖片跟屏幕一樣,也有1x模式,2x 模式。在 iPhone 6 Plus 中,還出現 3x 模式,原理是一樣的。


當 iPhone 4 選中 [email protected] 的圖片,就會生成一張大小爲 30 x 40 個點,2x 模式的圖片。這個時候,圖片看起來就會很清晰了。而沒有適配的舊程序,[email protected] 不存在,就選中 example.png,生成大小爲 30 x 40 個點,1x 模式的圖片,看起來比較模糊。但它們佔據的屏幕點數是一樣的。


iPhone 5

2012 年,蘋果發佈 iPhone 5。我們將所有機型對比,依然採用點作爲單位。

跟 iPhone 4 做比較, iPhone 5 的寬度保持不變。高度增加 568 - 480 = 88 個點。


在 iOS 開發中,44 這個數字比較特殊。iOS 界面指南寫着,人類的手指有一定大小,點擊區域低於 44 個點的時候,就難以點中。44 的兩倍就是 88。


當原有程序沒有適配 iPhone 5 的時候,也可以正常運行,但多出來的 88 個點將會將會被自動均分爲上下兩部分,使得上下出現黑邊。我找不到好看的圖片。

那麼怎樣才能告訴 iOS 系統,應用程序已經適配了 iPhone 5 呢?在這裏,我們先扯開一下,談一下啓動圖片。


點擊主屏幕的圖標,進入 App 的時候,會立即顯示一張圖片,這張圖片就是啓動圖片(Launch Image)。App 在正式啓動的時需要做一些初始化處理,這通常比較費時。先出現啓動圖片,可以使用戶覺得系統立即有響應,減少等待的焦慮感。


每個機型,比如同時支持 iPhone 和 iPad 的程序,需要分別爲 iPhone 跟 iPad 指定啓動圖片。當舊的 iPhone 4 的程序,運行在 iPhone 5 上面,沒有 iPhone 5 的啓動圖片,就採用兼容模式,上下留黑邊。當爲 iPhone 5 指定了新的啓動圖片,系統就認爲這個應用程序是已經適配了 iPhone 5 的,上下就不會留黑邊了。下面是微信啓動圖片,應該都很熟悉了。

微信啓動圖片中出現的那個地球,叫藍色彈珠(The Blue Marble),是在 1972 年 12 月 7 日由阿波羅 17 號太空船的船員所拍攝的。這張照片當年很震撼,是普通人第一次可以通過照片直接看到地球的全貌。


微信的啓動圖,爲適配iPhone 5,相比與iPhone 4, 很明顯狹長了。

典型iPhone應用程序(遊戲除外),很多是上面一個導航欄,下面一個工具欄或者標籤欄, 中間一大塊用於顯示的內容區。iPhone 5 拉長了,對於程序的適配,也不算麻煩,內容區的內容基本是動態生成的。適配時候可以簡單上下不變,中間的內容區拉長就行了。注意,導航欄和工具欄的高度也是 44 個點。下面是同一程序,在 iPhone 4 跟 iPhone 5 的對比。


AutoLayout

到了這個時候,傳統絕對定位的弱點就顯露出來了。這時 iPhone 按照點作爲單位,已經出現了兩種不同尺寸的屏幕,算上 iPad, 就有 3 種尺寸(有些 App 可以同時兼容 iPhone 和 iPad,稱爲 Universal)。


從iOS 6系統發佈後,iOS開發中可以採用一種 AutoLayout 的技術。AutoLayout 就像網頁一樣,指定 View,Button,Text 之間的相對位置,比如靠左多少,靠右多少,居中多少等等。舉個例子,像下面的簡單佈局。

假設左上角的區域爲 view1, 右上角的區域爲 view2, 下面的區域爲 view3。AutoLayout 會說:

1
2
3
4
5
6
7
8
9
10
11
12
view1.left = 20 // View1 的左邊距離邊界 20 個點
view1.top = 20 // View1 的上邊距離邊界 20 個點
view2.right = 20 // View2 的右邊距離邊界 20 個點
view2.top = 20 // View2 的上邊距離邊界 20 個點
view2.left = view1.right + 20 // View2 的左邊距離 View1 右邊 20 個點
view2.width = view1.width // View1 的寬度等於 View2 的寬度
view2.height = view1.height // view1 高度等於 view2 高度
view3.left = view1.left // view3 的跟 view1 左對齊
view3.right = view2.right // view3 跟 view2 右對齊
view3.top = view1.bottom + 20 // view3 的上邊距離 view1 下邊 20 個點
view3.bottom = 20 // view3 下邊距離邊界 20 個點
view3.height = view1.height // view3 高度等於 view1 高度

指定上面的約束條件後,AutoLayout 就會自動算出對應的佈局。上面我寫得比較繁瑣,事實上很多操作都是可以使用鼠標拖拉來指定的,並不一定需要使用代碼。但就算用代碼,也有簡寫的方法。下面是在 xib 中,拖拉鼠標指定約束時的界面。

而絕對定位,會直接說

1
2
3
view1.frame = (x1, y1, width1, height1)
view2.frame = (x2, y2, width2, height2)
view3.frame = (x3, y3, width3, height3)

絕對定位並非指定約束條件,而是開發者自己來精確指定 View,Button, Text 等的實際座標大小。


對於一個屏幕,絕對定位可能跟 AutoLayout 的區別不算大,甚至絕對定位會更方便些。但當需要同時適配多個屏幕,AutoLayout 根本不需要更改。而絕對定位就需要根據屏幕大小,一個個算出來。比如橫屏,在 AutoLayout 下面,就自動變成:

這裏不過是 3 個控件的佈局,當出現的控件數越多,屏幕尺寸越多,AutoLayout 的優勢就顯露出來了。另外 AutoLayout 有個好處是容易支持多語言,不同語言下,同一個意思文字的長度是不同的,使用 AutoLayout 也可以自動適配。


在 iOS 6 的時候,AutoLayout 還比較少人使用,當時屏幕尺寸還比較少。iOS 7 的時候,就開始很多人使用了。而到現在 iOS 8 了, 更加上 iPhone 6, iPhone 6 Plus 需要適配,AutoLayout 大勢所趨,不用不行了。


iPhone 6和iPhone 6 Plus

2014 年,iPhone 6和iPhone 6 Plus 發佈後,情況又有新的變化。再次比較所有 iPhone 機型。

屏幕尺寸再度分裂。但是我們比較 iPhone 5 跟 iPhone 6 的寬高比例。

可以看出,iPhone 6 跟 iPhone 5 雖然屏幕尺寸改變了,但是它們的比例是不變的。都是 9 ÷ 16 = 0.5625 的屏幕。


當舊的 iPhone 5 程序運行在 iPhone 6 上面,假如沒有經過適配,舊程序自動等比放大,鋪滿新手機,舊程序也可以正常運行。這種方案可算是自動適配。但因爲舊程序拉伸了,整體看起來有點虛,也不能更好利用大屏空間。


當需要開發者手動適配的時候,跟 iPhone 4 過渡到 iPhone 5 一樣,在新程序中,指定一張新的啓動圖片。當指定了啓動圖,屏幕分辨率就已經變成應有的大小,這時候利用 AutoLayout 進行佈局,同一份代碼,就可以支持多個機型。新手機的屏幕更大,有更多的虛擬點,可以顯示更多的內容。


值得注意一點是,iPhone 6 Plus。它的寬高是 414 × 736 個點,3x 模式,理想上來說,應該有 1242 × 2208 像素。但 iPhone 6 Plus 的實際像素是 1080 × 1920,是比理想值要少一點的。iPhone 6 Plus 的處理方式是將程序整體稍微縮小一點。分辨率很高,這點區別,實際上也看不出來。


那爲什麼需要這樣做呢?上面表格中 iPhone 6, iPhone 6 Plus 屏幕寬高的邏輯點的數字是怎麼來的?下面我猜測一下原因,但不能證實。


先看 iPhone 6,這個比較簡單。iPhone 6 的屏幕寬高比例跟 iPhone 5 一樣,使用對角線來計算,就是放大了 4.7 ÷ 4 = 1.175 倍。用這個數字,乘以 iPhone 5 的 320 x 568 個點,忽略誤差,差不多就是 iPhone 6 屏幕的 375 x 667 個點。這裏需要注意,屏幕寬高比例一樣,才能使用對角線來計算。


按照上面的方式來計算 iPhone 6 Plus, 應該是得到 440 x 781 個點,實際上卻是 414 × 736 個點。這裏我猜測是因爲,iPhone 6 Plus 屏幕明顯更大,相同尺寸的點放在大的屏幕上面,會使得人感覺尺寸變小,所以就將每個點的實際尺寸放大一些,從而得到更少的點數目。人眼看東西會有種錯覺,並非是孤立的看的,而是跟周圍的環境作比較。


確定了點數目之後,再確定了像素 1080 × 1920(很多高清電視就是這個尺寸),應該是 1080/414=2.6x,但 2.6x 這個數字開發就太麻煩了,就按照 3x 來處理。其實假如像素達到 1242 × 2208,3x 下也可以精確到 1:1, 這樣會更好。但現今的技術在考慮電池,處理器,屏幕尺寸等綜合因素下,很可能達不到這樣的細膩程度。


上述只是猜測,我相信那些手機參數是經過反覆考慮再確定的。iPhone 6 Plus 這個處於手機跟平板中間地帶的產物經過不少特殊處理。


由分析可以看到,慢慢的爲了適配多個機型,程序的啓動圖片也逐漸增多,爲解決這個問題。iOS 8 之後,可以使用 xib 來搭建啓動界面,這樣就可以同一個啓動界面,適配多個機型,減少啓動圖片佔用的空間。

建議


  • 以後的應用程序,都使用 AutoLayout, 不要再用絕對定位。

  • 使用類似網頁的方式來設計界面。

  • 設計師好,程序員也好,儘量使用點這個單位進行思考,而不要使用像素。比如,你需要做 44 x 66 個點的按鈕,2x 模式,就乘以 2, 3x 模式就乘以 3。這樣的思考方式可以大致估計到真實的物理長度。44 個點,就是手機上導航欄,工具欄的高度。假如用像素思考,容易使得做出的圖片過大或者過小。

  • 非矢量素材,就可以做尺寸最大的,之後再進行縮小。比如你需要兼容 3x 的屏幕,就直接做最高那種圖片。

  • 而當使用 Flash 之類的矢量工具來做素材的時候,應該直接做點那個尺寸。比如 44 x 66 個點的按鈕。就建立一個 44 x 66 的場景。之後再導出成 2 倍圖,3 倍圖,因爲矢量放大不失真。不要建立一個 3x 的場景,導出成大圖片,再進行縮小,這樣就容易失真。更理想的是直接使用矢量圖。

  • 假如是那種導航欄,工具欄之類的背景圖,需要橫跨整個屏幕。可以只切一小塊,讓程序拉伸,拉伸方式是保持兩邊的像素不動,只拉伸最中間的一列像素。需要拉伸的話,橫方向就不要出現一些漸變色。

  • 按鈕的點擊區域,不應該少於 44 像素,就算按鈕的圖片看起來比較小,也應該使得點按鈕周圍的透明區也有反應。

  • 可以按照你當前最方便測試機子的型號來做一些主要預覽圖,效果圖。比如你手頭有 iPhone 5,可以按照 iPhone 5 的尺寸,320 x 568 個點,需要兼容 iPhone 6 Plus,就使用 3x 的模式。這樣方便將圖片放進手機裏面看實際的效果。有多個測試機,就選較大的,之後再進行一些細調。假如支持 iPhone 6 Plus 的橫屏模式,需要另外處理。

  • 上面說的是應用的處理方式,遊戲會有些特殊。現在很多遊戲,按照 1136 x 768 的像素尺寸來設計場景,這樣可以同時兼容 iPad 和 iPhone,並只使用一份圖。iPad 1x 模式下尺寸是 1024 x 768 像素,iPhone 5 在 2x 模式下,是 1136 * 640 像素。這種尺寸,可以將場景居中顯示,各自將場景拉伸到最大。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章