文章出處


title: 2016-5-5未命名文件
tags: UI適配,圖片資源
grammar_cjkRuby: true
---

概述:
本文整理了Android開發中,圖片資源的提供方式和使用方式。包括圖片文件的文件組織,nine-path圖片,系統選擇不同設備針對的圖片時的規則等。可以在Android開發文檔中,Develop > API Guide > App Resources 目錄找到有關應用資源的更全面的介紹。
Note: 在Android 3.2之后的版本,有新的資源組織方式,本文只側重關于早先的資源的組織方式的整理。

1.為什么提供不同設備配置的資源文件

除代碼外,資源文件也是安卓程序中必不可少的部分,如圖片、布局文件,甚至是音頻、視頻等原始多媒體文件。不同于代碼文件的是,UI資源文件是和設備的顯示器密切相關的。目前,Android設備的配置種類繁多——不同的屏幕尺寸,分辨率,以及用戶使用時的不同的屏幕方向等。為了讓自己的程序運行在多種不同的尺寸上都表現良好,Android系統提供了很多有用的方式。例如,為不同的尺寸和分辨率的屏幕提供不同的圖片資源,這樣可以讓你的應用在不同的設備上顯示最適合此設備分辨率/尺寸的不同大小的圖片。
總之,在UI表現上,考慮為不同設備提供不同的資源是必不可少的做法。

2.Android屏幕配置相關概念

2.1 像素pixel/px

像素就是顯示器上顯示的一個最小的點,整個顯示屏就是一個由像素點組成的矩形。例如720*1280的像素就是說屏幕在橫豎分別有720和1280個可顯示的點。目前來講像素點都是一個正方形的“點”,它是最小的顯示單位。

2.2 PPI

Pixels Per Inch:每英寸的像素數,表示每英寸所擁有的像素數量。因此PPI數值越高,即代表顯示屏能夠以越高的密度顯示圖像。

2.3 DPI

Dot Per Inch:每英寸的點數。這里的“點”是一個抽象概念,例如打印機中,點就是。。。在電子顯示器中,DPI和PPI通常是混用的。

DPI和PPI都是描述設備的顯示密度的,它們本身不是長度單位,而是一個密度系數。

2.4 像素密度

Android中對圖片的分類是通過Screen pixel density (像素密度:以dpi為數值單位)進行的,包括ldpi、mdpi、hdpi、xhdpi這四個主要的級別。
ldpi: Low-density screens; approximately 120dpi.
mdpi: Medium-density (on traditional HVGA) screens; approximately 160dpi.
hdpi: High-density screens; approximately 240dpi.
xhdpi: Extra high-density screens; approximately 320dpi。
xhdpi:480dpi。

這四種屏幕密度之間存是3:4:6:8的縮放比例,所以,一個ldpi下的9x9像素的bitmap(位圖)在mddpi下就是12x12,在hdpi下是18x18,在xhdpi下是24x24。

2.5 Android對屏幕的分類

Android用兩個屬性size和density來對屏幕分類:
屏幕尺寸:small, normal, large, xlarge,xxlarge。

  • xlarge :screens are at least 960dp x 720dp
  • large screens are at least 640dp x 480dp
  • normal :screens are at least 470dp x 320dp
  • small :screens are at least 426dp x 320dp

像素密度:low (ldpi), medium (mdpi), high (hdpi), extra high (xhdpi), extra extra high (xhdpi)。

屏幕尺寸和像素密度都有各自的分級,它們是相互獨立的。大屏幕可以是小的分辨率,而小屏幕可以是大分辨率。

2.6 DP的使用

對于Android開發,布局文件中可以使用px(pixel像素)這樣的絕對單位,而更多情況下,根據Android開發的適配方式,應使用的UI元素的大小單位是“dp”即“dip”,device independent pixels(設備獨立像素)。
它是一個虛擬的像素單位,以像素無關的方式來表示UI元素的尺寸和位置。
設備最終顯示時,UI上的任何元素都是需要一個具體的像素值的,那么dp是如何轉換為最終的像素值的?
正如DIP它的名字,它表示一種邏輯單位,和實際pxiel之間存在著轉換關系,系統會自動在不同設備像素密度時把以dp為單位的大小縮放為合適的具體像素值。
具體做法是:

像素密度分級mdpi為基準,它的dpi值為160,此時1dp = 1px。對于運行程序的設備,Android系統會根據其尺寸和屏幕像素來計算出它的像素密度分級。不同像素密度下dp和px的轉換不同,公式是: px = dp * (dpi / 160),根據公式可以知道,不同像素密度下的dp轉換為px時對應的縮放比例和它們之間的dpi值是成正比的。那么在xhdpi下,其dpi為320,則1dp為2px,正好是mdpi的2倍。

下面是bitmap的例子:
在為應用提供bitmap資源時,應該保證圖片可以正確被縮放到不同的像素密度級別。
對于一個圖片,它在不同像素密度級別下的縮放系數如下:

  • xhdpi: 2.0
  • hdpi: 1.5
  • mdpi: 1.0 (參考標準)
  • ldpi: 0.75

如果在xhdpi的設備下使用的合適的圖片尺寸是200x200,那么在hdpi下圖片應該是150x150,在mdpi下是100x100,在ldpi下是75x75.

目前手機的像素密度至少都在mdpi及以上,所有通常只提供xhdpi和xxhdpi下的圖片即可,像素密度小的設備,Android系統會將位圖進行合適的縮放。

以dp為尺寸和位置,使得UI元素在不同屏幕上擁有一致的表現。原理就是“等比縮放”,方式就是dp,dp的概念和對應px的計算方式如上面所記。即便使用dp來在不同的dpi下進行縮放轉換,如果屏幕的大小(例如同樣的dpi但是一個是5寸、一個是8寸平板)、寬高比例(4:3、16:9、16:10等)是不一樣的,還是會出現個別的UI顯示問題。這就需要借助良好的UI布局設計來避免內容顯示不全、錯位...等問題。對于形形色色的屏幕,沒有一種方案是萬能的。

優缺點:
等比縮放:位圖失真,沒有充分利用大屏幕顯示更多的內容。
不等比縮放:滿足寬高都顯示完整,其余的和等比縮放一樣。
靈活的布局排版:設計上去避免不同尺寸的屏幕顯示問題最好。

2.7 size和density資源組織的不同

The types of alternative resources you should create depends on your application's needs. Usually, you should use the size and orientation qualifiers to provide alternative layout resources and use the density qualifiers to provide alternative bitmap drawable resources.
為不同尺寸的屏幕提供不同特定的layout文件,對不同的像素米的屏幕提供不同的drawable資源。

3.多個備選圖片資源的組織

以dp指定的寬高和位置數值,系統會自動縮放到合適的像素數值。對于drawable 資源(bitmap: .png, .jpg, and .gif 、Nine-Patch: .9.png),系統也會根據當前的設備像素密度來對它進行縮放——當為ImageView這樣的控件指定以dp為單位的大小,或者為wrap_content時,在不同的像素密度的屏幕上其顯示的像素大小是不一樣的。若只提供單一的圖片資源,在縮放后圖片往往會變得模糊與期望不一樣,所以圖片,尤其是位圖,需要針對不同的像素密度來提供不同的合適的像素尺寸的圖片。
所以,需考慮對不同的像素密度的屏幕提供不同的圖片資源。在Android項目中,圖片資源的組織,正是按照pixel density來進行不同屏幕的分組。
drawable 資源放在res目錄下不同的子目錄中——使用不同的像素密度修飾符對應不同的像素密度:

  • drawable-ldpi/ :對應ldpi
  • drawable-mdpi/ :對應mdpi
  • drawable-hdpi/ :對應hdpi
  • drawable-xhdpi/ :對應xhdpi
  • drawable-xxhdpi/ :對應xxhdpi

根據應用需要適配的屏幕范圍,提供對應的圖片資源到drawable-(density qualifiers)目錄下。

Note: You only need to provide density-specific drawables for bitmap files (.png, .jpg, or .gif) and Nine-Path files (.9.png). If you use XML files to define shapes, colors, or other drawable resources, you should put one copy in the default drawable directory (drawable/).

4.系統對圖片資源的選擇規則和使用方式

對應一個代碼中用到的圖片資源,Android系統會使用以下步驟來選擇出最適合當前運行設備的圖片資源文件進行顯示:

  1. 系統尋找匹配當前屏幕像素密度的可用圖片文件。
    例如當前設備屏幕像素密度分級為xhdpi則使用drawable-xhdpi目錄下的文件。
  2. 如果沒有找到匹配的文件,系統使用默認的圖片資源,并對它進行縮放。
    系統會使用合適的圖片,進行縮放。例如,設備像素密度為ldpi,應用提供了hdpi的圖片,那么系統會選擇對hdpi的圖片縮放0.5。最后的情況是,如果沒有任何與當前像素密度合適的圖片,系統選則默認的default resources(目錄不包含配置修飾符,即drawable目錄)——對應mdpi的像素密度。

為不同的密度的屏幕提供圖片時,確保在統一的幾個密度分級之間按照3:4:6:8的比例。
例如,假設在mdpi下提供的launcher icon為48x48像素,那么在其它密度下的尺寸分別為:

  • 36x36 for low-density
  • 48x48 for medium-density
  • 72x72 for high-density
  • 96x96 for extra high-density

5.UI適配的技巧

5.1 指導

  • Use wrap_content, fill_parent, or dp units when specifying dimensions in an XML layout file ,Similarly, you should prefer the sp (scale-independent pixel) to define text sizes. The sp scale factor depends on a user setting and the system scales the size the same as it does for dp.
  • Do not use hard coded pixel values in your application code
  • Do not use AbsoluteLayout (it's deprecated)
  • Use size and density-specific resources,Supply alternative bitmap drawables for different screen densities.

5.2 代碼中dp和px的轉換

public static int dip2px(Context context, float dipValue) {
    final float scale = context.getResources().getDisplayMetrics().density;
    return (int) (dipValue * scale + 0.5f);
}

public static int px2dip(Context context, float pxValue) {
    final float scale = context.getResources().getDisplayMetrics().density;
    return (int) (pxValue / scale + 0.5f);
}

6.Nine-Patch圖片的使用

Android中提供兩種方式在屏幕上繪制圖像:Canvas、和Drawable。
Canvas: 代碼中繼承自View后重寫onDraw等方法。
Drawable:resource images、resource XML、ShapeDrawable和Nine-patch。

靜態圖片資源(可以是多種備選)中.9.png是特殊的一種,在UI適配時很常用。

如果UI中使用到的位圖需要在系統拉伸某個View之后依然填充此View(例如按鈕的背景圖片),那么就應該使用NinePatch圖片,它的指定的部分可以被任意拉伸。所以,使用一個NinePatch就可以適配所有尺寸的屏幕。不過,對不同的密度的屏幕,依然需要提供不同的NinePatch。

九宮格圖片是一種可拉伸的位圖,在作為其它View的背景顯示時,Android系統會自動將它改變到一個合適的大小。例如一個Button的長度隨其顯示的文本變化時,作為Button的背景的NinePatch圖片也會自動被拉伸。
九宮格圖片是一個標準的png文件,它包含一個額外的“1-像素-寬度”的邊界。九宮格圖片的名稱必須以 .9.png作為后綴。針對不同像素密度的NinePatch圖片放在不同的drawable-xxx里面。

NinePatch的邊界用來定義它的可拉伸區域和靜態區域(內容填充區域),通過在左、上邊界上指定一個或多個1-pixel-wide黑色的線段——線段上的像素點就是可以在拉伸時被重復的點。這些線段在拉伸時保持相對的大小。

右、下邊界可以分別指定1個線段(不能是多個)來確定背景的內容填充區——也就是View的內容可以填充的區域,類似padding地作用。如果不指定,那么系統以邊長除去兩邊一像素的線段作為填充區域的線段。

由于Nine-patch圖片的特殊使用方式,應該注意它的最小尺寸,保證有一個點的可拉伸區域。例如一個10像素半徑的圓角矩形,邊長至少為21,其中一個點是拉伸區域。

參考資料

在Android開發文檔 4.4 中:

  • API Guide > Animation and Graphics > Canvas and Drawables
    ./sdk/docs/guide/topics/graphics/2d-graphics.html

  • API Guide > App Resources > Providing Resources
    ./sdk/docs/guide/topics/resources/providing-resources.html

  • API Guide > Best Practices > Supporting Multiple Screens
    ./sdk/docs/guide/practices/screens_support.html

  • Training > Getting Started > Supporting Different Devices
    ./sdk/docs/training/basics/supporting-devices/screens.html

  • Design > Style > Iconography
    ./sdk/docs/design/style/iconography.html

  • Training > Best Practices for User Interface > Designing for Multiple Screens
    ./sdk/docs/training/multiscreen/index.html


文章列表


不含病毒。www.avast.com
arrow
arrow
    全站熱搜
    創作者介紹
    創作者 AutoPoster 的頭像
    AutoPoster

    互聯網 - 大數據

    AutoPoster 發表在 痞客邦 留言(0) 人氣()