Google berkomitmen untuk mendorong terwujudnya keadilan ras bagi komunitas Kulit Hitam. Lihat caranya.

Mendukung kepadatan piksel yang berbeda

Perangkat Android tidak hanya hadir dalam berbagai ukuran layar (handset, tablet, TV, dan sebagainya), tetapi juga layarnya memiliki berbagai ukuran piksel. Maksudnya, perangkat yang satu memiliki 160 piksel per inci persegi, sedangkan perangkat lainnya sesuai dengan 480 piksel dalam ruang yang sama. Jika Anda tidak mempertimbangkan perbedaan ini dalam kepadatan piksel, sistem mungkin menskalakan gambar Anda (yang mengakibatkan gambar blur) atau gambar mungkin muncul dalam ukuran yang benar-benar salah.

Halaman ini menunjukkan cara mendesain aplikasi untuk mendukung berbagai kepadatan piksel menggunakan satuan pengukuran yang tidak dipengaruhi oleh resolusi dan memberikan resource bitmap alternatif untuk setiap kepadatan pikselnya.

Tonton video berikut ini untuk ringkasan tentang teknik ini.

Untuk informasi selengkapnya tentang mendesain aset ikon aktual, lihat panduan ikon desain material.

Menggunakan piksel kepadatan mandiri

Kesalahan pertama yang harus dihindari adalah menggunakan piksel untuk menentukan jarak atau ukuran. Menentukan dimensi layout dengan piksel menjadi masalah karena layar yang berbeda memiliki kepadatan piksel yang berbeda pula, jadi jumlah piksel yang sama bisa sesuai dengan ukuran fisik yang berbeda pada perangkat yang berbeda.

Gambar 1. Dua layar dengan ukuran yang sama bisa memiliki jumlah piksel yang berbeda

Untuk mempertahankan ukuran UI Anda yang terlihat pada layar dengan kepadatan berbeda, Anda harus mendesain UI menggunakan piksel kepadatan mandiri (dp) sebagai unit pengukuran Anda. Satu dp adalah satuan piksel virtual yang kira-kira setara dengan satu piksel pada layar kepadatan medium (160 dpi; kepadatan "dasar pengukuran"). Android akan menerjemahkan nilai ini dalam jumlah tepat piksel aktual untuk masing-masing kepadatan.

Misalnya, pertimbangkan kedua perangkat dalam gambar 1. Jika Anda ingin menetapkan lebar tampilan menjadi "100px", tampilan akan tampak jauh lebih besar pada perangkat sebelah kiri. Jadi, sebagai gantinya Anda harus menggunakan “100dp” untuk memastikan ukurannya sama di kedua layar.

Namun, saat menentukan ukuran teks, Anda harus menggunakan piksel skalabel (sp) sebagai satuan pengukuran (tetapi jangan pernah menggunakan sp untuk ukuran tata letak). Satuan sp memiliki ukuran yang sama dengan dp, secara default, tetapi ukuran dalam satuan ini berubah berdasarkan ukuran teks pilihan pengguna.

Misalnya, saat Anda menentukan spasi antara dua tampilan, gunakan dp:

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

Saat menentukan ukuran teks, selalu gunakan sp:

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

Mengonversikan satuan dp menjadi satuan piksel

Dalam beberapa kasus, Anda perlu menyatakan dimensi dalam dp kemudian mengonversinya menjadi piksel. Konversi satuan dp ke piksel layar cukup sederhana:

px = dp * (dpi / 160)

Bayangkan sebuah aplikasi dengan gestur scroll atau mengayun yang akan dikenali setelah jari pengguna berpindah setidaknya 16 piksel. Pada layar dasar pengukuran, jari pengguna harus berpindah setidaknya sejauh 16 pixels / 160 dpi, yang sama dengan 1/10 inci (atau 2,5 mm) sebelum gestur dikenali. Pada perangkat yang memiliki tampilan berkepadatan tinggi (240 dpi), jari pengguna harus berpindah sejauh 16 pixels / 240 dpi, yang sama dengan 1/15 inci (atau 1,7 mm). Jarak tersebut jauh lebih pendek sehingga aplikasi tampak lebih sensitif bagi pengguna.

Untuk memperbaiki masalah ini, nilai minimum gestur harus dinyatakan dengan kode dalam dp kemudian dikonversi menjadi piksel sesungguhnya. Contoh:

Kotlin

    // The gesture threshold expressed in dp
    private const val GESTURE_THRESHOLD_DP = 16.0f
    ...
    private var mGestureThreshold: Int = 0
    ...
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // Get the screen's density scale
        val scale: Float = resources.displayMetrics.density
        // Convert the dps to pixels, based on density scale
        mGestureThreshold = (GESTURE_THRESHOLD_DP * scale + 0.5f).toInt()

        // Use mGestureThreshold as a distance in pixels...
    }
    

Java

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

    // Get the screen's density scale
    final float scale = getResources().getDisplayMetrics().density;
    // Convert the dps to pixels, based on density scale
    mGestureThreshold = (int) (GESTURE_THRESHOLD_DP * scale + 0.5f);

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

Kolom DisplayMetrics.density menentukan faktor penskalaan yang harus Anda gunakan untuk mengonversi satuan dp menjadi piksel, sesuai dengan kepadatan piksel saat ini. Pada layar berkepadatan medium, DisplayMetrics.density sama dengan 1,0; pada layar berkepadatan tinggi, sama dengan 1,5; pada layar berkepadatan ekstra-tinggi, sama dengan 2,0; dan pada layar berkepadatan rendah, sama dengan 0,75. Angka ini adalah faktor yang melipatgandakan satuan dp untuk mendapatkan jumlah piksel aktual untuk layar saat ini.

Menggunakan nilai konfigurasi yang diskalakan sebelumnya

Anda bisa menggunakan class ViewConfiguration untuk mengakses jarak, kecepatan, dan waktu yang biasa digunakan oleh sistem Android. Sebagai contoh, jarak dalam piksel yang digunakan oleh framework sebagai nilai minimum scroll dapat diperoleh dengan getScaledTouchSlop():

Kotlin

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

Java

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

Metode-metode dalam ViewConfiguration yang dimulai dengan awalan getScaled dijamin akan mengembalikan nilai dalam piksel yang akan menampilkan kepadatan layar saat ini dengan benar.

Menyediakan bitmap alternatif

Untuk memberikan kualitas grafis pada perangkat dengan kepadatan piksel berbeda, Anda harus menyediakan beberapa versi masing-masing bitmap dalam aplikasi, satu untuk setiap bucket kepadatan, pada resolusi yang sesuai. Jika tidak, Android harus menskalakan bitmap Anda agar menempati ruang terlihat yang sama di setiap layar, sehingga mengakibatkan artefak penskalaan seperti blur.

Gambar 2. Ukuran relatif untuk bitmap pada ukuran kepadatan yang berbeda

Ada beberapa bucket kepadatan yang tersedia untuk digunakan di aplikasi Anda. Tabel 1 menjelaskan berbagai kualifikasi konfigurasi yang tersedia dan jenis layar yang bisa diterapkan dengannya.

Tabel 1. Kualifikasi konfigurasi untuk berbagai kepadatan piksel.

Kualifikasi kepadatan Deskripsi
ldpi Resource untuk layar kepadatan rendah (ldpi) (~120 dpi).
mdpi Resource untuk layar kepadatan medium (mdpi) (~160 dpi). (Kepadatan ini adalah dasar pengukuran.)
hdpi Resource untuk layar kepadatan tinggi (hdpi) (~240 dpi).
xhdpi Resource untuk layar kepadatan ekstra tinggi (xhdpi) (~320 dpi).
xxhdpi Resource untuk layar kepadatan ekstra ekstra tinggi (xxhdpi) (~480 dpi).
xxxhdpi Resource untuk penggunaan kepadatan ekstra ekstra ekstra tinggi (xxxhdpi) (~640 dpi).
nodpi Resource untuk semua kepadatan. Ukuran ini adalah resource kepadatan mandiri. Sistem tidak menskalakan resource yang diberi tag dengan penentu ini, berapa pun kepadatan layar saat ini.
tvdpi Resource untuk layar di antara mdpi dan hdpi; sekitar 213 dpi. Ukuran ini tidak dianggap sebagai kelompok kepadatan utama". Kepadatan ini utamanya ditujukan untuk televisi dan sebagian besar aplikasi tidak memerlukannya, menyediakan resource mdpi dan hdpi sudah cukup untuk sebagian besar aplikasi dan sistem yang akan menskalakan sebagaimana mestinya. Jika merasa perlu menyediakan resource tvdpi, Anda harus menyetel ukurannya pada faktor 1,33* mdpi. Misalnya, gambar resolusi 100 px x 100 px untuk layar mdpi seharusnya menjadi 133 px x 133 px untuk tvdpi.

Agar dapat membuat bitmap drawable alternatif untuk kepadatan yang berbeda, Anda harus mengikuti skala rasio 3:4:6:8:12:16 antara enam kepadatan utama. Misalnya, jika Anda memiliki bitmap drawable berukuran 48x48 piksel untuk layar berkepadatan medium, semua ukuran yang berbeda harus sebesar:

  • 36x36 (0,75x) untuk kepadatan rendah (ldpi)
  • 48x48 (1,0x dasar pengukuran) untuk kepadatan medium (mdpi)
  • 72x72 (1,5x) untuk kepadatan tinggi (hdpi)
  • 96x96 (2,0x) untuk kepadatan ekstra tinggi (xhdpi)
  • 144x144 (3,0x) untuk kepadatan ekstra ekstra tinggi (xxhdpi)
  • 192x192 (4,0x) untuk kepadatan ekstra ekstra ekstra tinggi (xxxhdpi)

Kemudian, tempatkan file gambar yang dibuat pada subdirektori yang tepat di bawah res/ dan sistem akan memilih file yang benar secara otomatis berdasarkan kepadatan piksel pada perangkat tempat aplikasi Anda berjalan:

    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
    

Kemudian, kapan saja Anda mereferensikan @drawable/awesomeimage, sistem akan memilih bitmap yang tepat berdasarkan dpi layar. Jika Anda tidak memberikan resource kepadatan khusus untuk kepadatan tersebut, sistem akan memilih pencocokan terbaik berikutnya dan menskalakannya agar sesuai dengan layar.

Tips: Jika Anda memiliki beberapa resource drawable yang tidak boleh diskalakan oleh sistem (mungkin karena Anda menjalankan beberapa penyesuaian pada gambar pada waktu proses), Anda harus memasukkannya dalam direktori dengan kualifikasi konfigurasi nodpi. Resource dengan kualifikasi ini dianggap tidak bergantung pada kepadatan tertentu dan sistem tidak akan menskalakannya.

Untuk informasi selengkapnya tentang kualifikasi konfigurasi lain dan cara Android memilih resource yang tepat untuk konfigurasi layar saat ini, lihat Menyediakan Resource.

Meletakkan ikon aplikasi di direktori mipmap

Seperti halnya aset bitmap lainnya, Anda perlu menyediakan versi kepadatan khusus ikon aplikasi Anda. Namun, beberapa peluncur aplikasi menampilkan ikon aplikasi Anda 25% lebih besar dari yang dipanggil oleh bucket kepadatan perangkat.

Misalnya, jika bucket kepadatan perangkat adalah xxhdpi dan ikon aplikasi terbesar yang Anda sediakan berada dalam drawable-xxhdpi, aplikasi peluncur akan meningkatkan skala ikon ini, dan menjadikannya tampak kurang jelas. Jadi, Anda harus menyediakan ikon peluncur dengan kepadatan yang lebih tinggi di direktori mipmap-xxxhdpi. Kini peluncur bisa menggunakan aset xxxhdpi.

Karena skala ikon aplikasi Anda mungkin ditingkatkan seperti ini, Anda harus meletakkan semua ikon aplikasi pada direktori mipmap bukan direktori drawable. Tidak seperti direktori drawable, semua direktori mipmap dipertahankan di APK meskipun Anda mem-build APK kepadatan khusus. Hal ini memungkinkan aplikasi peluncur untuk memilih ikon resolusi terbaik untuk ditampilkan di layar utama.

    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
    

Untuk panduan desain ikon, lihat panduan penting tentang ikon.

Untuk membantu mem-build ikon aplikasi, lihat Membuat Ikon Aplikasi dengan Image Asset Studio.

Menggunakan grafik vektor

Alternatif untuk membuat beberapa versi spesifik kepadatan sebuah gambar adalah membuat hanya satu grafis vektor. Grafis vektor membuat gambar menggunakan XML untuk menentukan jalur dan warna, bukan menggunakan bitmap piksel. Dengan demikian, grafik vektor dapat menskalakan hingga berbagai ukuran tanpa artefak penskalaan, meskipun grafik vektor paling baik digunakan dalam hal ilustrasi seperti ikon, bukan foto.

Grafik vektor sering disediakan sebagai file SVG (Scalable Vector Graphics), tetapi Android tidak mendukung format ini sehingga Anda harus mengonversi file SVG ke format vektor drawable milik Android.

Anda bisa dengan mudah mengonversi SVG ke vektor drawable dari Android Studio menggunakan Vector Asset Studio seperti berikut ini:

  1. Di jendela Project, klik kanan di direktori res, lalu pilih Baru > Aset Vektor.
  2. Pilih File lokal (SVG, PSD).
  3. Temukan file yang ingin Anda impor, kemudian lakukan penyesuaian.

    Gambar 3. Mengimpor SVG dengan Android Studio

    Anda mungkin melihat beberapa error muncul di jendela Asset Studio, yang menunjukkan beberapa properti file yang tidak didukung oleh vektor drawable. Namun, hal ini tidak akan mencegah Anda dalam mengimpor, properti yang tidak didukung akan diabaikan begitu saja.

  4. Klik Selanjutnya.

  5. Pada layar berikutnya, konfirmasi set sumber tempat file akan dimasukkan dalam project Anda, lalu klik Selesai.

    Karena satu vektor drawable dapat digunakan pada semua kepadatan piksel, file ini akan masuk ke direktori drawable default (Anda tidak perlu menggunakan direktori kepadatan khusus):

        res/
          drawable/
            ic_android_launcher.xml
        

Untuk informasi selengkapnya tentang pembuatan grafik vektor, baca dokumentasi Vektor Drawable.

Saran untuk masalah kepadatan yang tidak biasa

Bagian ini menjelaskan lebih lanjut tentang cara Android menjalankan penskalaan untuk bitmap pada kepadatan piksel yang berbeda dan cara Anda bisa mengontrol bagaimana bitmap digambar pada kepadatan yang berbeda. Kecuali aplikasi memanipulasi grafis atau Anda mengalami masalah saat berjalan di kepadatan piksel yang berbeda, Anda dapat mengabaikan bagian ini.

Untuk memahami bagaimana Anda bisa mendukung beberapa kepadatan ketika memanipulasi grafis pada waktu proses secara lebih baik, Anda harus memahami bahwa sistem membantu memastikan skala yang tepat untuk bitmap dengan cara berikut:

  1. Prapenskalaan terhadap resource (misalnya drawable bitmap)

    Berdasarkan kepadatan layar saat ini, sistem menggunakan resource kepadatan khusus apa pun dari aplikasi Anda. Jika resource tidak tersedia dalam kepadatan yang benar, sistem akan memuat resource default dan menskalakannya ke atas atau ke bawah sesuai kebutuhan. Sistem menganggap bahwa resource default (resource dari direktori tanpa kualifikasi konfigurasi) didesain untuk kepadatan piksel dasar pengukuran (mdpi) dan akan mengubah ukuran bitmap tersebut menjadi ukuran yang sesuai dengan kepadatan piksel saat ini.

    Jika Anda meminta dimensi resource yang telah diskalakan sebelumnya, sistem akan menampilkan nilai yang mewakili dimensi tersebut setelah penskalaan. Misalnya, bitmap yang didesain pada ukuran 50x50 piksel untuk layar mdpi akan diskalakan ke 75x75 piksel pada layar hdpi (jika tidak ada resource alternatif untuk hdpi) dan sistem akan melaporkan ukuran tersebut.

    Ada beberapa situasi yang mungkin membuat Anda tidak ingin Android melakukan prapenskalaan terhadap resource. Cara termudah untuk menghindari prapenskalaan adalah memasukkan resource dalam direktori resource dengan pengontrol kualitas konfigurasi nodpi. Contoh:

    res/drawable-nodpi/icon.png

    Saat sistem menggunakan bitmap icon.png dari folder ini, sistem tidak akan menskalakannya berdasarkan kepadatan perangkat saat ini.

  2. Penskalaan otomatis dimensi dan koordinat piksel

    Anda dapat menonaktifkan dimensi dan gambar prapenskalaan dengan menyetel android:anyDensity ke "false" dalam manifes atau secara terprogram untuk Bitmap dengan menyetel inScaled ke "false". Pada kasus ini, sistem akan otomatis menskalakan nilai koordinat piksel absolut dan nilai dimensi piksel apa pun pada waktu menggambarnya. Sistem melakukannya untuk memastikan elemen layar yang ditentukan dengan piksel tetap ditampilkan pada ukuran fisik yang kurang lebih sama karena akan ditampilkan pada kepadatan pixel dasar pengukuran (mdpi). Sistem menangani penskalaan ini secara transparan ke aplikasi dan melaporkan dimensi piksel yang diskalakan ke aplikasi, bukan dimensi piksel fisik.

    Sebagai contoh, anggaplah sebuah perangkat memiliki layar berkepadatan tinggi WVGA 480x800 dan ukurannya kurang lebih sama dengan layar HVGA biasa, tetapi perangkat menjalankan aplikasi yang menonaktifkan prapenskalaan. Dalam hal ini, sistem akan "berbohong" kepada aplikasi ketika membuat kueri untuk dimensi layar dan melaporkan 320x533 (perkiraan terjemahan mdpi untuk kepadatan piksel). Kemudian, saat aplikasi melakukan operasi menggambar, misalnya menjadikan persegi panjang tidak valid dari (10,10) hingga (100, 100), sistem akan mentransformasikan koordinat dengan menskalakannya ke jumlah yang tepat, dan benar-benar membuat region (15,15) hingga (150, 150) menjadi tidak valid. Perbedaan tersebut dapat menyebabkan perilaku yang tidak terduga jika aplikasi Anda secara langsung memanipulasi bitmap yang telah diskalakan, tetapi hal ini dianggap sebagai konsekuensi wajar untuk mempertahankan performa aplikasi sebaik mungkin. Jika Anda mengalami kondisi tersebut, baca Mengonversi satuan dp ke satuan piksel.

    Normalnya, Anda tidak perlu menonaktifkan prapenskalaan. Cara terbaik untuk mendukung beberapa layar adalah dengan mengikuti teknik dasar yang dideskripsikan dalam dokumen ini.

Jika aplikasi Anda memanipulasi bitmap atau berinteraksi secara langsung dengan piksel pada layar pada cara lain, Anda mungkin perlu mengambil langkah tambahan untuk mendukung kepadatan layar yang berbeda. Misalnya, jika Anda merespons gestur sentuh dengan menghitung jumlah piksel yang dilalui oleh jari, Anda perlu menggunakan nilai piksel kepadatan mandiri, bukan piksel aktual, tetapi Anda bisa dengan mudah mengonversi antara nilai dp dan px.

Menguji di semua kepadatan piksel

Penting untuk menguji aplikasi Anda pada beberapa perangkat dengan kepadatan piksel berbeda sehingga Anda bisa memastikan penskalaan UI dengan benar. Menguji perangkat fisik itu mudah, tetapi Android Emulator juga bisa digunakan jika Anda tidak memiliki akses ke perangkat fisik untuk semua kepadatan piksel yang berbeda.

Jika Anda lebih memilih untuk mengujinya pada perangkat fisik tetapi tidak ingin membeli perangkat, Anda dapat menggunakan Firebase Test Lab untuk mengakses perangkat di pusat data Google.