標籤:android blog http io os ar 使用 sp strong
前言
安卓是一個只對硬體裝置限制有很少限制的移動作業系統。生產商們幾乎可以創造任何形狀的、尺寸的和密度的螢幕的裝置。裝置可以有物理鍵盤和按鈕或者只有虛 擬鍵盤和按鈕。由於它的裝置客制化的自由性給軟體開發人員們製造了一些麻煩。首先,應用軟體怎樣在各種各樣的裝置上保證一致的使用者體驗呢?其次,應用軟體怎 樣利用一些擁有高端硬體或者獨特特性的裝置的優勢呢?安卓在當初研發的時候就考慮了這些,給開發人員提供了一些工具去支援各種配置的裝置,最佳化了不同配置的 裝置的使用者體驗,這些將在下面介紹。
為了應用程式的靈活性和相容任何配置的裝置,認真思考合適的跨配置的使用者體驗是必須的。建立一個Android應用程式時,設計者和開發人員必須建立一個無 論是在小尺寸的手機上還是在大尺寸的平板上都能運行良好的UI介面。他們還要考慮圖片資源對高密度和低密度的螢幕的最佳化。這篇BLOG的中心就是安卓怎樣 支援不同密度的螢幕。
安卓的基本設計思想就是保證使用者介面中的元素擁有相同的物理大小,而不論螢幕的密度。為什麼呢?很簡單,無論什麼樣的螢幕密度一個使用者的手指的物理尺寸是 不變的。按鍵或者可以按的元素在任何裝置上應該渲染成和手指物理大小一樣尺寸(比手指印大一點)。文本和字母在不同的裝置上也應該渲染成一樣的字型大小 (可讀的)。
螢幕密度不等於解析度
螢幕像素密度是解析度和顯示尺寸的比值,可以用每英吋像素點或者dpi來度量。dpi越高,每個像素點越小也就越清晰。簡單地說,dpi越高就意味著每英 寸顯示的細節越多,而不是直接取決於高分辨。舉個例子,Galaxy Nexus(對角線 4.65‘‘)解析度為:720x1280,Nexus 7(對角線 7‘‘)解析度為:800x1280.常見的錯誤觀點是認為他們擁有相同的螢幕像素密度,因為它們的解析度幾乎一樣。然而,Galaxy Nexus 的螢幕像素密度約為316dpi,Nexus 7的螢幕像素密度為216dpi,相差甚遠。這是因為雖然它們擁有一樣的解析度,但是它們顯示尺寸卻不一樣。再次說明,螢幕像素密度是解析度和顯示尺寸的 比值,兩個因素一起決定螢幕像素密度。
密度層級
無數的Android裝置的像數密度各不相同,分布為100dpi到480dpi以上。為那些不同密度的螢幕最佳化圖片,就必須建立不同解析度的圖片。然 而,嘗試為所有的像數密度最佳化所有的圖片資源將會使是讓人無法想象的無聊乏味,同時引起應用程式大小變的臃腫,簡單的方法是不可行的。作為折衷方 案,Android用密度層級的概念把擁有確定密度範圍的裝置分類。這樣應用程式只需要針對每個密度層級來最佳化圖片,而不是針對所有可能的像素密度來優 化。這使得設計者和開發人員的工作負擔是合理的,時阻止了應用程式大小的膨脹。當然,代價就是:不同像素密度的裝置片渲染後的物理尺寸是大小不一的,這 點將會在後面介紹。
因此,設計者和開發人員如何根據密度塊來最佳化圖片資源?首先,要決定的是圖片的呈現尺寸。例如,一個表徵圖試圖在螢幕中呈現 0.5x0.5的大小。下一步,建立一個圖片支援的最大密度,或者是一個可伸縮的向量圖。最好的做法是支援最大的密度,當前是在xxhdpi 就在480dpi.在480dpi,一張0.5x0.5的圖片轉換為240x240px.一旦圖形資源的最大密度版本被建立在240x240px.那麼它 就可以在隨後建立的密度塊版本被適當的縮小比例,每個版本用相同的檔案名稱。Google建議不要在213dpi建立tvdpi版本,因為它僅僅是被特定的 應用程式所需要,並且被一小撮裝置而使用。一旦所有的版本被建立,它們可以被添加到drawable檔案夾,並且用資源標識符告訴Android系統每一 種密度塊所需要的大小。最後,參考一下在xml布局層的圖形資源,然後通過編碼它們的名稱在R檔案中產生,R檔案是一個可以在程式中引用所有資源的檔案。 Android系統會在運行時載入資源,並盡它最大的努力去匹配實際的裝置配置與資源標識符應用。假如任何圖片資源的密度版本沒有被包括在 內,Android將用另外的密度版本並且將它縮小到所需要的合適的尺寸大小。當然,不推薦讓Android系統來這樣做。因為Andorid系統在操作 圖片資源時並沒有圖片編輯軟體操作的更加有 效和精確。
尺寸單位
在安卓中,使用者介面可以在xml檔案中建立或在在代碼中實現。有幾種單位可以用來表示一個表單的長寬。它們可以用在很多元素上來設定寬、高、外間距、內間距等等。
px——螢幕上真實的像素。這是一個與像素密度有關聯的單位,一px單位的物理大小取決於螢幕的像素密度。
in——螢幕上的物理英寸。這是一個與像素密度無關聯的單位,一in單位的物理大小在任何像素密度的螢幕上都是一樣大的。一in單位轉化為多少px單位取決於螢幕的像素密度。
mm——螢幕上的物理毫米。這是一個與像素密度無關聯的單位,一mm單位的物理大小在任何像素密度的螢幕上都是一樣大的。25.4mm等於一in。一mm單位轉化為多少px單位取決於螢幕的像素密度。
pt——點,螢幕上普通字型大小單位。這是一個與像素密度無關聯的單位,一pt單位的物理大小在任何像素密度的螢幕上都是一樣大的。72pt等於一in。一pt單位轉化為多少px單位取決於螢幕的像素密度。
dp——像素密度無關聯的像素單位。這是一個與像素密度無關聯的單位。然而一dp單位的物理大小在不同的像素密度螢幕上只是近視的相等。大約160dp等於一in。在一dp轉化為160dpi中的一個比例因素是與裝置的密度層級相關聯的。一dp等於多少像素取決於螢幕的像素密度和裝置所屬的密度層級。
s
p——大小獨立的像素單位,特地指定text的大小。這是一個與像素密度無關聯的單位。然而一
sp單位的物理大小在不同的像素密度螢幕上只是近視的相等。在一
sp轉化為160
dpi中的一個比例因素是與裝置的密度層級以及字型表現的大小相關聯的。一
sp等於多少像素取決於螢幕的像素密度和裝置所屬的密度層級。
神奇的“dp”
如前面討論的那樣,"px"不是密度獨立的,並且在不同的裝置上擁有不同的大小,然而"in","mm"和"pt"是密度獨立的,當然在不同的裝置上擁有相同的大小。但是,"dp"和"sp"跟其餘的有一些不同,雖然他們是密度獨立的,但是他們在 不同的裝置上擁有不同的大小。這是為什麼呢?答案是"dp"和"sp"是如何被計算成像素的。Android使用mdpi(160dpi)作為其標準密 度,這裡 1dp就是1px。本質上來講,"dp"可以被認為是在160 dpi上的“px”。這就是為什麼160 dp轉換為大約1 in。因此根據裝置密度等級與標準的密度(mdpi)之間的比率來轉換"dp"到"px"。
"dp"趨向於不同的物理大小的原因是由於相同的縮放因子被應用到整個密度桶。該縮放因子是計算密度桶dpi,而不是裝置真實的 dpi。當裝置的dpi不完全地與它的密度桶dpi相同的時候,相同數目的"dp"轉換為相同量的"px"。這就會導致相同數目的"px"被顯示到不同密 度的螢幕上,以不同的大小呈現出來。
上面的表格顯示了100 dp如何在不同密度的裝置上轉換為"px"。100 dp應該大致地轉化為0.625 in,並且完美地轉換為bucket sizes。但是,當裝置的dpi少於密度桶的dpi的時候,它的像素在物理上會更大,並且相同數目的"dp"會渲染得更大,反之亦然。
因此這就引出一個問題,為什麼"dp"允許這種物理尺寸的變化?從根本上來說,android在物理尺寸上會犧牲一些精確度,目的是為了保持效能和顯示質 量。由於利用android的密度桶比率(0.75:1.0:1.5:2.0:3.0)讓"dp"縮放到"px",這就允許有極小的"px"舍入和簡單的 估計。同時,由於縮放因子與密度桶比率成比例,“dp”會按比例顯示為各種密度提供的圖片資源。最後,當縮放圖行的時候,最好保持接近整數和簡單的分數,因為複雜的分數會導致圖片顏色過渡異常和走樣。
定義UI元素的界限
當定義使用者介面元素的長寬時有幾個特別的選項可供選擇,就像尺寸單位一樣。
wrap_content——這個選項將會擴充元素的邊界到足夠的大小以致可以容納它包含的內容(圖片,文本等等),本質上,這個選項把元素設定成它最大子項目的大小,不會去調整元素的大小。
match_parent(fill_parent 在API 8中已淘汰)——這個選項會使元素適應父元素的大小,使用父元素最大的空間,減少間距。本質上,這使子項目為父元素允許的最大尺寸的大小,並且必要的時候會調整元素的大小。
dimension unit——這個選項設定元素的邊界為精確地單位大小,這些單位上文已經討論過。本質上,它會設定元素的邊界為確定的單位大小,必要的時候會調整元素的大小。Demo
為瞭解釋這一切是如何一起工作的,建立並測試一個應用程式範例是必要的。例如,採用一個在密度為xhdpi或320dpi,200X200 px的圖片的設計。簡單起見,將圖片資源命名為“android_logo”。利用密度在320dpi,200X200 px映像解析度作為所需的物理尺寸,可替換的映像尺寸可以被計算出來。
密度為xhdpi (320dpi),200x200px 的圖片
在計算完所需特定密度的映像尺寸後,他們能夠在最大密度版本被縮小到相應的尺寸,如前面所解釋的那樣。接下來,每一個密度版本的圖片,能夠被放入到用相應資源標識符標記的“drawable”檔案夾下。Android系統會根據裝置上的配置,在運行時選擇最佳的資源。
有標識符的資來源目錄
現在,為了呈現保持密度獨立的可能方式,利用每一種密度獨立的尺寸單位,將該圖片設定成相同的物理尺寸。因為"px"不是密度獨立的,而"sp"是為text設計的,因此忽略它們。
裝置例子:xhdpi Bucket
通過使用一個布局,裡麵包含相同的圖片,這些圖片是利用各種尺寸單位設定相同的物理大小,它可以比較每個尺寸單位是如何工作的。當運行在320 dpi的模擬器上,圖片會以完全相同的大小顯示,每一個尺寸單位都是這樣。這是意料之中的,因為模擬器的dpi完全符合xhdpi(320 dpi)密度等級。但是,當運行在同樣xhdpi 密度等級的Galaxy Nexus上時,圖片的大小尺寸會有一些變化。
320dpi 模擬器
Galaxy Nexus
經過檢查發現,很顯然用"wrap_content"和"dp"設定的圖片在大小上是匹配的,與此同時,用"in","mm"和"pt"也是匹配的。但 是,這兩組沒有彼此匹配。到底發生了什麼事情呢?如之前討論,"wrap_content"和"dp"利用密度桶比率去適當地轉換它們的尺寸。因此,圖片 大小被計算到200x200 px。但是,Galaxy Nexus的實際螢幕密度並不是320 dpi,它是 315.3 xdpi和 318.7 ydpi。 因為實際的密度低於320 dpi的xhdpi密度,因此在實際裝置上的像素點會比想象的0.625 in的物理大小更大。
當分析用"in","mm"和"pt"設定圖片大小的時候,注意到每一個圖片被轉換為 197.1x199.2 px。如之前討論,"in","mm"和"pt"都是利用實際裝置的密度去轉換它們的尺寸到像素。因為Galaxy Nexus的實際密度低於320 dpi的xhdpi密度,更少的像素需要被轉換為0.625x0.625 in,這樣圖片就被縮小了。
當對所顯示的圖片進行對比時,很明顯,用"wrap_content"和"dp"設定的圖片物理尺寸精確度較低,但是它們的圖片品質比"in","mm"和"pt"更好。
沒有縮放"wrap_content"和"dp"(左)。有縮放"in","mm"和"pt"(右)
裝置例子: hdpi Bucket
下一步,當運行在240dpi的模擬器上時,圖片以完全相同的大小顯示每一個尺寸單元。重複一下,之所以期望這樣是由於模擬器的dpi在240dpi的條 件下恰好匹配hdpi密度的桶(bucket)。但像以前一樣,當運行於hdpi裝置時,出現一個不可思議的事情,映像的尺寸有一些變化。
240dpi模擬器螢幕
HTC Droid Incredible
像往常一樣,HTC Droid Incredible顯示150x150 px的圖片,該圖片用"wrap_content" 和"dp"設定。因為Droid Incredible的實際螢幕密度為254x254dpi,大於240dpi的hdpi密度,這意味著在螢幕上的像素小於240 dpi密度對應像素的大小。這就會導致150x150 px的圖片顯示要小於0.625 in的基礎大小。用"in","mm"和"pt"設定的圖片顯示為158.8x158.8px,因為需要更多的像素點轉換為0.625x0.625 in,這樣該圖片就會被放大。
就像在Galaxy Nexus上,用"wrap_content"和"dp"設定的圖片物理尺寸精確度較低,但是它們的圖片品質比"in","mm"和"pt"更好。
沒有縮放"wrap_content"和"dp"(左)。有縮放"in","mm"和"pt"(右)
你能在GitHub找到該demo所有的源碼,或從後面的附件中獲得。
尺寸單位最佳實務
px- 沒有保持密度獨立。應該永遠不需要。
in/mm/pt- 保持密度獨立,但是計算到確切數額的像素,會降低體驗,還會導致圖片顏色過渡不自然和走樣。如果需要尺寸大小的精確度,並且任何偏差都是不可接受的,那選擇in/mm/pt就是必要的。需要確切距離的時候,設定元素間的距離,in/mm/pt也是很有用的。
dp- 保持密度獨立並且保持最佳圖片品質,但是要在物理大小上,以小的偏差作為代價。因為它利用密度桶比率來進行計算大小,它適當地提供準確的尺寸與圖片資源。這是被推薦使用的尺寸單位,用來設定元素間的界限或者之間的距離。
sp- 保持密度獨立和字型的品質,但是要在物理大小上,以小的偏差作為代價。這是被推薦使用的尺寸單位,僅僅用來設定字型大小,因為它需要考慮密度和使用者的文字大小偏好。
總結
總的來說,保持密度獨立性的要點:
- 確定每一個映像資源確定呈現該資源所需的物理尺寸
- 設計尺寸比最大密度桶更大的向量映像資源或原始映像資源
- 為每一個密度桶建立特定的density 版本,然後將他們放入用合適標識符標識的“drawable”資來源目錄下
- 當設定映像邊界的時候,用“wrap_content”來獲得最佳顯示效果,用“match_parent”來充滿整個顯示地區,或者用“dp”來設定一個固定的尺寸
- 當在布局裡面設定距離的時候,用“dp”獲得最佳顯示效果。如果需要使用精確的尺寸,僅用“in”,"mm"或"pt"。在這裡永遠別使用"px"
隨著對Android如何處理在不同密度的螢幕上顯示的理解,這將使得在任何密度的顯示屏上設計和開發最佳的應用程式變得更加容易。
英文原文:Understanding Density Independence in Android
深入理解Android的密度獨立性