支援不同的像素密度

Android 裝置不僅有不同的螢幕大小,包括手機、平板電腦、電視、 等等,但也具有不同像素大小的螢幕。一 裝置的每英寸像素數可能為 160 像素,另一部裝置則可容納 480 像素。 顯示相同的像素只要不考慮在 可能會調整為 以免造成圖像模糊不清 大小不正確

本頁說明如何設計支援您的應用程式 使用與解析度無關的測量單位 並針對各個像素密度提供替代點陣圖資源

請觀看以下影片,概略瞭解這些技巧。

如要進一步瞭解如何設計圖示素材資源,請參閱 Material Design 圖示指南

使用密度獨立像素

避免使用像素來定義距離或尺寸。使用 不同螢幕的像素密度不同 因此相同的像素數量會對應至 不同的裝置

圖片:顯示兩種不同密度的裝置範例
圖 1:兩個相同大小的螢幕可能會有不同的像素數量。

保留 UI 的可見大小 並設計 UI 密度獨立像素 (dp) 做為測量單位。1 dp 虛擬像素單位,約在 medium 像素密度螢幕上約 1 像素 (160 dpi,或「基準」密度)。Android 會將這個值 每種像素密度的真實像素數量。

我們看圖 1 中的兩個裝置。檢視畫面 裝置左側顯示 100 像素寬的位置。檢視畫面 如果定義為 100 dp,兩個螢幕的寬度會相同。

定義文字大小時,您可以改為使用 可縮放 像素 (sp) 做為單位。sp 單位是 與 dp 相同,但預設會根據使用者的偏好調整大小 文字大小切勿使用 sp 做為版面配置大小。

舉例來說,如要指定兩個檢視畫面之間的間距,請使用 dp:

<Button android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/clickme"
    android:layout_marginTop="20dp" />

指定文字大小時,請使用 sp:

<TextView android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:textSize="20sp" />

將 dp 單位轉換為像素單位

在某些情況下,您必須以 dp 表示尺寸,接著 就會轉換成像素dp 單位與螢幕像素之間的轉換 如下:

px = dp * (dpi / 160)

注意:請勿將這個方程式進行硬式編碼,以便計算像素。而是改用 TypedValue.applyDimension(), ,可將許多類型的尺寸 (dp、sp 等) 轉換成像素。

假設應用程式可辨識捲動或快速滑過手勢 直到使用者的手指移動至少 16 像素。位於基準線 螢幕,使用者的手指必須在 16 pixels / 160 dpi 的位置 (相當於 1/10 英寸或 2.5 公釐) 移動螢幕, 手勢辨識成功

在裝置上 採用高密度螢幕 (240 dpi) 時,使用者的手指必須 16 pixels / 240 dpi,需要 等於 1/15 英寸 (或 1.7 公釐)。距離較短 因此對使用者而言,應用程式看起來會更靈敏。

如要解決這個問題,請在程式碼中以 dp 表示手勢門檻, 然後轉換成實際的像素例如:

Kotlin

// The gesture threshold expressed in dp
private const val GESTURE_THRESHOLD_DP = 16.0f

private var gestureThreshold: Int = 0

// Convert the dps to pixels, based on density scale
gestureThreshold = TypedValue.applyDimension(
  COMPLEX_UNIT_DIP,
  GESTURE_THRESHOLD_DP + 0.5f,
  resources.displayMetrics).toInt()

// Use gestureThreshold as a distance in pixels...

Java

// The gesture threshold expressed in dp
private final float GESTURE_THRESHOLD_DP = 16.0f;

// Convert the dps to pixels, based on density scale
int gestureThreshold = (int) TypedValue.applyDimension(
  COMPLEX_UNIT_DIP,
  GESTURE_THRESHOLD_DP + 0.5f,
  getResources().getDisplayMetrics());

// Use gestureThreshold as a distance in pixels...

DisplayMetrics.density 欄位 指定將 dp 單位轉換為的縮放係數 根據目前像素密度計算出來的像素。在中密度螢幕中 DisplayMetrics.density 等於 1.0,高密度螢幕則等於 1.5。在 extra-high 密度的螢幕上 等於 2.0,在低密度螢幕中則等於 0.75。這個圖形 「TypedValue.applyDimension()」已用於 取得目前畫面的實際像素數量。

使用預先縮放設定值

您可以使用 ViewConfiguration 類別存取 距離、速度和 Android 系統使用的時間。舉例來說, 取得的捲動門檻值 (以像素為單位) 搭配 getScaledTouchSlop()

Kotlin

private val GESTURE_THRESHOLD_DP = ViewConfiguration.get(myContext).scaledTouchSlop

Java

private final int GESTURE_THRESHOLD_DP = ViewConfiguration.get(myContext).getScaledTouchSlop();

ViewConfiguration 中的方法開頭為 getScaled 前置字串 保證會傳回正確顯示的值,無論目前設定為何 像素密度。

偏好向量圖形

除了建立多個特定密度的圖片版本之外, 只建立一個向量圖形向量圖形可以用 XML 建立圖像 定義路徑和顏色,而不使用像素點陣圖。因此向量 縮放成任何大小的圖片時 模型通常不會縮放成像 最適合用於圖示 (而非相片) 的插圖

向量圖形通常以 SVG (可擴充向量圖形) 檔案提供。 但 Android 不支援這種格式,因此您必須將 SVG 檔案 Android 的向量 可繪項目格式。

您可以使用 Android Studio 的 Vector Asset Studio 如下所示:

  1. 在「Project」視窗中的「res」目錄上按一下滑鼠右鍵,然後選取 新增 >Vector Asset
  2. 選取「Local file (SVG、PSD)」
  3. 找出你要匯入的檔案,並進行所需調整。

    顯示如何在 Android Studio 中匯入 SVG 的圖片
    圖 2:利用以下工具匯入 SVG Android Studio。

    您可能會在「Asset Studio」視窗中發現一些錯誤 表示向量可繪項目不支援檔案的某些屬性。 但無法防止您匯入檔案;不支援的屬性 系統會忽略此值。

  4. 點選「Next」

  5. 在下一個畫面中,確認要在專案中存放檔案的來源集。 然後按一下「完成」

    由於一個向量可繪項目可用於所有像素密度,因此這個檔案 位於預設的可繪項目目錄中,如下所示 階層您不需要使用像素密度專屬目錄。

    res/
      drawable/
        ic_android_launcher.xml
    

如要進一步瞭解如何建立向量圖形,請參閱向量可繪項目 說明文件。

提供替代點陣圖

為了在具有不同像素密度的裝置上提供良好的圖像品質, 為應用程式為每個點陣圖提供多個版本 和對應的解析度密度級別。否則,Android 必須 讓點陣圖佔用每個畫面上的相同可見空間 例如模糊等縮放失真

圖片:顯示不同密度大小的點陣圖相對大小
圖 3:不同密度級別的點陣圖相對大小。

您可以在應用程式中使用多種密度級別。資料表 1 說明各種可用的設定限定詞,以及何種螢幕類型 以及適用的模型

表 1. 設定限定詞 像素密度。

密度限定詞 說明
ldpi 適用於 low 像素密度 (ldpi) 螢幕的資源 (約 120 dpi)。
mdpi 適用於 medium 像素密度 (mdpi) 螢幕的資源 (約 160 dpi)。這是基準 。
hdpi 適用於高密度 (hdpi) 螢幕的資源 (約 240 dpi)。
xhdpi 適用於 extra-high 像素密度 (xhdpi) 螢幕的資源 (約 320 dpi)。
xxhdpi 適用於 extra-extra-high 密度 (xxhdpi) 螢幕的資源 (約 480 dpi)。
xxxhdpi 適用於 extra-extra-extra-high 密度 (xxxhdpi) 螢幕的資源 (約 640 dpi)。
nodpi 適用於所有像素密度的資源,都屬於像素密度獨立資源。系統不會幹擾 縮放以此限定詞標記的資源 (無論目前螢幕的密度為何)。
tvdpi 適用於 mdpi 與 hdpi 之間螢幕的資源;大約 約 213 dpi。這並不是「主要的」像素密度分組,主要用於設計 ,而且大多數應用程式都不需要使用此限定詞,例如提供 mdpi 和 hdpi 就足以滿足大多數應用程式的需求,系統會按照 或適當。如果您認為必須提供 tvdpi 資源, 大小為 1.33 * mdpi。例如將 100x100 像素的圖片 mdpi 螢幕為 tvdpi 的 133 x 133 像素。

如要為不同密度建立替代點陣圖可繪項目,請遵循 6 個主要密度之間的縮放比例為 3:4:6:8:12:16舉例來說 針對 medium 像素密度螢幕而言,點陣圖可繪項目為 48x48 像素,大小如下:

  • 36x36 (0.75x),適用於 low 像素密度 (ldpi)
  • 48x48 (1.0x 基準),適用於中密度 (mdpi)
  • 72x72 (1.5 倍),適用於高密度 (HDPI)
  • 96x96 (2.0x),適用於 extra-high 像素密度 (xhdpi)
  • 144x144 (3.0x),適用於 extra-extra-high 密度 (xxhdpi)
  • 192 x 192 (4.0x),適用於 extra-extra-extra-high 密度 (xxxhdpi)

將產生的圖片檔放在合適的子目錄中 低於 res/

res/
  drawable-xxxhdpi/
    awesome_image.png
  drawable-xxhdpi/
    awesome_image.png
  drawable-xhdpi/
    awesome_image.png
  drawable-hdpi/
    awesome_image.png
  drawable-mdpi/
    awesome_image.png

之後當您參照 @drawable/awesomeimage 時, 系統會根據螢幕的 dpi,選取適當的點陣圖。如果發生以下情況: 未針對該密度提供像素密度專屬資源,系統就會 下一個最符合的項目,並調整成適合螢幕的大小。

提示:如果您有可繪製資源 如不希望系統擴充配置 請自行在執行階段中對圖片做出一些調整, 並在目錄中使用 nodpi 設定限定詞 含有此限定詞的資源視為各種密度通用,且 就無法擴充資源

如要進一步瞭解其他設定限定詞和 Android 如何選擇適當的資源 目前的畫面設定,請參閱「應用程式資源總覽」一文。

將應用程式圖示放在 mipmap 目錄中

和其他點陣圖素材資源一樣,您必須提供特定密度的 應用程式圖示。不過,部分應用程式啟動器會顯示應用程式圖示,高度為 25% 大於裝置密度級別所呼叫的 值。

舉例來說,假設裝置的密度級別為 xxhdpi,而您最大的應用程式圖示 提供位於 drawable-xxhdpi,應用程式啟動器會放大這個圖示。 讓圖片看起來較不清晰

為避免這種情況,請將 應用程式圖示位於 mipmap 目錄中,而非 drawable 目錄中。取消喜歡 drawable 目錄,所有 mipmap 目錄都會保留在 APK 中,即使 建構應用程式所需的密度專屬 APK這可讓啟動器應用程式挑選 解析度圖示。

res/
  mipmap-xxxhdpi/
    launcher_icon.png
  mipmap-xxhdpi/
    launcher_icon.png
  mipmap-xhdpi/
    launcher_icon.png
  mipmap-hdpi/
    launcher_icon.png
  mipmap-mdpi/
    launcher_icon.png

以前一個 xxhdpi 裝置的例子來說,您可以 mipmap-xxxhdpi 目錄中的高密度啟動器圖示。

如需圖示設計指南,請參閱「系統圖示」。

如需建構應用程式圖示的說明,請參閱「使用 Image Asset Studio 建立應用程式圖示」一文。

罕見密度問題的建議

本節說明 Android 如何縮放點陣圖 以及如何進一步控制 點陣圖是以不同的密度繪製而成除非您的應用程式操弄圖形 或是在不同的像素密度執行時發生問題 可以忽略這一節的內容

如要進一步瞭解您在操控 因此,你必須知道系統如何協助確保點陣圖的適當縮放比例。 方法如下:

  1. 預先縮放資源,例如點陣圖可繪項目

    系統會根據目前螢幕的密度,使用任何特定密度。 從您的應用程式中設定資源如果 正確密度,系統會載入預設資源,並視需求放大或縮小。系統會假設預設資源 (例如來自 沒有設定限定詞的目錄),則是專為基準測試而設計 像素密度 (mdpi),並將這些點陣圖調整為適當的大小 目前的像素密度

    如果您要求了預先縮放資源的維度,系統就會傳回值 表示縮放「之後」的維度。例如,設計為 50x50 像素的點陣圖 mdpi 螢幕在 hdpi 螢幕上會縮放為 75x75 像素 (如果沒有替代資源的話) 時,系統會回報此大小。

    在某些情況下,您可能不希望 Android 預先縮放 資源如要避免預先縮放,最簡單的方式就是將資源放入資源目錄 並使用 nodpi 設定限定詞例如:

    res/drawable-nodpi/icon.png

    系統使用這個資料夾中的 icon.png 點陣圖時,系統不會縮放 自動調整資源配置

  2. 自動調整像素維度和座標的縮放比例

    如要停用預先縮放的尺寸和圖片,請設定 android:anyDensityinScaled 設為 "false",透過程式輔助方式將 Bitmap 設為 "false"。於 此時,系統會自動縮放任何絕對像素座標和像素 維度值這個過程可確保像素 螢幕元素仍以大致相同的實際大小顯示 可在基準像素密度 (mdpi) 顯示。系統會處理 這個縮放比例對應用程式來說是公開透明 並回報經過縮放的像素 而非實體像素尺寸。

    舉例來說,假設裝置有 WVGA 高密度螢幕,也就是 480x800, 與傳統 HVGA 螢幕大小相同,但正在執行的應用程式已停用 自動調整資源配置在此情況下,系統會「落在」應用程式查詢 維度,前者是 320x533,代表像素密度的近似 mdpi 轉譯。

    之後 應用程式會執行繪圖作業,例如將 (10,10) 到 (100) 的矩形失效。 100),系統會對座標進行適當縮放來轉換座標,然後實際 將區域 (15,15) 失效為 (150、150)。這項差異可能導致非預期的行為, 您的應用程式會直接操控縮放過的點陣圖,但這是合理的 權衡取捨,確保應用程式發揮最佳效能。如果遇到這種情況 遇到這種情況時,請參閱將 dp 單位轉換為像素 單元

    通常不停用預先縮放功能。支援多種 畫面就是遵循本頁所述基本技巧。

如果應用程式會操控點陣圖或直接與螢幕上的像素互動 換個方式,您可能需要採取額外步驟 像素密度。舉例來說,如果您以數字形式回應觸控手勢, 代表手指交叉的像素數量,您必須使用適當的 密度獨立像素值,而非實際像素,但您可以 在 dp 和 px 值之間轉換

測試所有像素密度

使用不同像素在多部裝置上測試應用程式 密度,以便確保 UI 正確縮放。在實體機器上測試 裝置;請使用 Android 模擬器 (如果您沒有實體存取權) 適合各種像素密度的裝置

如果您想在實體裝置上測試 如果不想購買裝置,可以使用 Firebase Test Lab: 存取 Google 資料中心內的裝置