Farklı piksel yoğunluklarını destekleme

Android cihazların yalnızca farklı ekran boyutları (cihazlar, tabletler, TV'ler vb.) değil, aynı zamanda farklı piksel boyutlarına sahip ekranları da vardır. Bir cihaz inç başına 160 piksel, başka bir cihaz ise aynı alana 480 piksel sığabilir. Piksel yoğunluğundaki bu farklılıkları dikkate almazsanız sistem, resimlerinizi ölçeklendirerek bulanık resimlere neden olabilir veya resimler yanlış boyutta görünebilir.

Bu sayfada, çözünürlükten bağımsız ölçü birimleri kullanarak ve her piksel yoğunluğu için alternatif bit eşlem kaynakları sağlayarak farklı piksel yoğunluklarını destekleyecek şekilde uygulamanızı nasıl tasarlayabileceğiniz gösterilmektedir.

Bu tekniklere genel bir bakış için aşağıdaki videoyu izleyin.

Simge öğeleri tasarlama hakkında daha fazla bilgi için Materyal Tasarım simge yönergelerine bakın.

Yoğunluktan bağımsız pikseller kullanın

Mesafeleri veya boyutları tanımlamak için piksel kullanmaktan kaçının. Farklı ekranlarda farklı piksel yoğunlukları olduğundan, boyutların piksellerle tanımlanması bir sorun teşkil eder. Bu nedenle, aynı piksel sayısı farklı cihazlarda farklı fiziksel boyutlara karşılık gelir.

Farklı yoğunluklara sahip iki örnek cihazı gösteren resim
Şekil 1: Aynı boyuttaki iki ekran farklı sayıda piksele sahip olabilir.

Farklı yoğunluklara sahip ekranlarda kullanıcı arayüzünüzün görünür boyutunu korumak için kullanıcı arayüzünüzü ölçüm birimi olarak yoğunluktan bağımsız pikselleri (dp) kullanarak tasarlayın. Bir dp, orta yoğunluklu ekranda (160 dpi veya "referans" yoğunluk) yaklaşık bir piksele eşit olan sanal bir piksel birimidir. Android bu değeri birbirlerinin yoğunluğu için uygun gerçek piksel sayısına çevirir.

Şekil 1'de gösterilen iki cihazı düşünün. 100 piksel genişliğindeki bir görünüm, soldaki cihazda çok daha büyük görünür. 100 dp genişliğinde olarak tanımlanan bir görünüm, her iki ekranda da aynı boyutta görünür.

Metin boyutlarını tanımlarken, birimleriniz olarak bunun yerine ölçeklenebilir pikselleri (sp) kullanabilirsiniz. sp birimi varsayılan olarak dp ile aynı boyuttadır ancak kullanıcının tercih ettiği metin boyutuna göre yeniden boyutlandırılır. Düzen boyutları için hiçbir zaman sp kullanmayın.

Örneğin, iki görünüm arasındaki boşluğu belirtmek için dp kullanın:

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

Metin boyutunu belirtirken, sp kullanın:

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

dp birimlerini piksel birimlerine dönüştürün

Bazı durumlarda, boyutları dp cinsinden ifade etmeniz ve daha sonra bunları piksellere dönüştürmeniz gerekir. dp birimlerinin ekran piksellerine dönüştürülmesi aşağıdaki şekildedir:

px = dp * (dpi / 160)

Not: Pikselleri hesaplamak için hiçbir zaman bu denklemin kodunu gömmeyin. Bunun yerine, birçok boyut türünü (dp, sp vb.) sizin için piksele dönüştüren TypedValue.applyDimension() özelliğini kullanın.

Kullanıcının parmağı en az 16 piksel hareket ettikten sonra bir kaydırma veya saldırma hareketinin tanındığı bir uygulama düşünün. Temel ekranda, hareketin tanınması için kullanıcının parmağıyla 16 pixels / 160 dpi hareketinin 1/10 cm'ye (veya 2,5 mm) eşit olması gerekir.

Yüksek yoğunluklu ekranı (240 dpi) olan bir cihazda kullanıcının parmağı 16 pixels / 240 dpi hareket etmelidir.Bu da bir inçin 1/15'ine (veya 1,7 mm) eşittir. Mesafe çok daha kısa ve bu sayede uygulama kullanıcıya daha duyarlı görünüyor.

Bu sorunu düzeltmek için hareket eşiğini dp cinsinden kodda ifade edin ve daha sonra, gerçek piksellere dönüştürün. Örneğin:

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 alanı, dp birimlerini geçerli piksel yoğunluğuna göre piksellere dönüştürmek için kullanılan ölçek faktörünü belirtir. DisplayMetrics.density, orta yoğunluklu bir ekranda 1,0, yüksek yoğunluklu ekranda 1,5'e eşittir. Ekstra yüksek yoğunluklu bir ekranda 2,0'a, düşük yoğunluklu bir ekranda ise 0, 75'e eşittir. Bu değer, TypedValue.applyDimension() tarafından geçerli ekranın gerçek piksel sayısını almak için kullanılır.

Önceden ölçeklendirilmiş yapılandırma değerlerini kullan

Android sistemi tarafından kullanılan ortak mesafelere, hızlara ve sürelere erişmek için ViewConfiguration sınıfını kullanabilirsiniz. Örneğin, çerçevenin kaydırma eşiği olarak kullandığı piksel cinsinden mesafe, getScaledTouchSlop() ile elde edilebilir:

Kotlin

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

Java

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

ViewConfiguration alanında getScaled önekiyle başlayan yöntemlerin, mevcut piksel yoğunluğundan bağımsız olarak düzgün görüntülenen piksel cinsinden bir değer döndürmesi garanti edilir.

Vektörel grafikleri tercih et

Bir resmin yoğunluğuna özel birden fazla sürümünü oluşturmanın alternatifi, tek bir vektör grafiği oluşturmaktır. Vektör grafikleri, piksel bit eşlemleri kullanmak yerine yolları ve renkleri tanımlamak için XML kullanarak bir resim oluşturur. Bu nedenle, vektör grafikler, ölçekleme kusurları olmadan her boyuta ölçeklenebilir, ancak genellikle fotoğraflar için değil, simgeler gibi resimler için idealdir.

Vektör grafikler genellikle SVG (Ölçeklenebilir Vektör Grafiği) dosyası olarak sağlanır ancak Android bu biçimi desteklemediğinden SVG dosyalarını Android'in vektör çekilebilir biçimine dönüştürmeniz gerekir.

Android Studio'nun Vektör Asset Studio uygulamasını aşağıdaki şekilde kullanarak SVG'yi çizilebilir bir vektöre dönüştürebilirsiniz:

  1. Proje penceresinde, res dizinini sağ tıklayın ve Yeni > Vektör Öğesi'ni seçin.
  2. Yerel dosya (SVG, PSD) seçeneğini belirleyin.
  3. İçe aktarmak istediğiniz dosyayı bulun ve düzenlemeleri yapın.

    Android Studio&#39;da SVG&#39;lerin nasıl içe aktarılacağını gösteren resim
    Şekil 2: Android Studio ile SVG'yi içe aktarma.

    Asset Studio penceresinde, vektör çekilebilir öğelerinin dosyanın bazı özelliklerini desteklemediğini belirten bazı hatalar görebilirsiniz. Bu durum dosyayı içe aktarmanızı engellemez; desteklenmeyen özellikler yoksayılır.

  4. İleri'yi tıklayın.

  5. Bir sonraki ekranda, projenizde dosyanın bulunmasını istediğiniz kaynak grubunu onaylayın ve Son'u tıklayın.

    Tüm piksel yoğunluklarında bir tane çekilebilir vektör kullanılabildiğinden, bu dosya aşağıdaki hiyerarşide gösterildiği gibi varsayılan çizimler dizininize yerleştirilir. Yoğunluğa özel dizinler kullanmanız gerekmez.

    res/
      drawable/
        ic_android_launcher.xml
    

Vektör grafikleri oluşturma hakkında daha fazla bilgi için vektör çekilebilir belgelerini okuyun.

Alternatif bit eşlemler sağlama

Farklı piksel yoğunluklarına sahip cihazlarda iyi grafik kalitesi sağlamak için uygulamanızda her bit eşlemin birden fazla sürümünü (her yoğunluk paketi için bir tane, karşılık gelen çözünürlükte) sağlayın. Aksi takdirde, Android'in bit eşleminizi her ekranda aynı görünür alanı işleyecek şekilde ölçeklendirmesi gerekir. Bu da, bulanıklaştırma gibi ölçekleme yapılarına yol açar.

Farklı yoğunluk boyutlarında bit eşlemler için göreli boyutları gösteren resim
Şekil 3: Farklı yoğunluk paketlerindeki bit eşlemlerin göreli boyutları.

Uygulamalarınızda kullanabileceğiniz çeşitli yoğunluk paketleri vardır. Tablo 1'de, kullanılabilen farklı yapılandırma niteleyicileri ve bunların hangi ekran türlerine uygulandığı açıklanmaktadır.

Tablo 1. Farklı piksel yoğunlukları için yapı niteleyicileri kullanabilirsiniz.

Yoğunluk niteleyici Açıklama
ldpi Düşük yoğunluklu (ldpi) ekranlar için kaynaklar (~120 dpi).
mdpi Orta yoğunluklu (mdpi) ekranlar (~160 dpi) için kaynaklar. Bu, referans yoğunluktur.
hdpi Yüksek yoğunluklu (hdpi) ekranlar (~240 dpi) için kaynaklar.
xhdpi Ekstra yüksek yoğunluklu (xhdpi) ekranlar için kaynaklar (~320 dpi).
xxhdpi Ekstra yüksek yoğunluklu (xxhdpi) ekranlar (~480 dpi) için kaynaklar.
xxxhdpi Ekstra ekstra yüksek yoğunluk (xxxhdpi) kullanımları için kaynaklar (~640 dpi).
nodpi Her yoğunluk için kaynaklar. Bunlar yoğunluktan bağımsız kaynaklardır. Mevcut ekranın yoğunluğundan bağımsız olarak sistem, bu niteleyiciyle etiketlenen kaynakları ölçeklendirmez.
tvdpi mdpi ile hdpi arasında bir yerdeki ekranlar için kaynaklar; yaklaşık yaklaşık 213 dpi. Bu, "birincil" bir yoğunluk grubu olarak kabul edilmez. Çoğu uygulama için tasarlanmış olup çoğu uygulama buna ihtiyaç duymaz. Çoğu uygulama için mdpi ve hdpi kaynakları sağlamak yeterlidir. Sistem bu kaynakları uygun şekilde ölçeklendirir. tvdpi kaynakları sağlamanız gerekiyorsa kaynakları 1,33 * mdpi faktöründe boyutlandırın. Örneğin, mdpi ekranlar için 100x100 piksel bir resim, tvdpi için 133x133 pikseldir.

Farklı yoğunluklar için alternatif bit eşlem çekilebilirleri oluşturmak üzere altı birincil yoğunluk arasındaki 3:4:6:8:12:16 ölçeklendirme oranını uygulayın. Örneğin, orta yoğunluklu ekranlar için 48x48 piksel boyutunda bir bit eşlem çiziminiz varsa boyutları şu şekildedir:

  • Düşük yoğunluk (ldpi) için 36x36 (0,75x)
  • Orta yoğunluk (mdpi) için 48x48 (1,0x referans değer)
  • Yüksek yoğunluk (hdpi) için 72x72 (1,5x)
  • Ekstra yüksek yoğunluk (xhdpi) için 96x96 (2,0x)
  • Ekstra yüksek yoğunluk için (xxhdpi) 144x144 (3,0x)
  • Ekstra çok yüksek yoğunluk için (xxxhdpi) 192x192 (4,0x)

Oluşturulan resim dosyalarını res/ altındaki uygun alt dizine yerleştirin:

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

Daha sonra, @drawable/awesomeimage kaynağına başvuruda bulunduğunuzda sistem, ekranın dpi'sine göre uygun bit eşlemi seçer. Bu yoğunluk için yoğunluğa özel bir kaynak sağlamazsanız sistem bir sonraki en iyi eşleşmeyi bulur ve ekrana sığacak şekilde ölçeklendirir.

İpucu: Sistemin ölçeklendirmesini istemediğiniz çekilebilir kaynaklarınız varsa (örneğin, çalışma zamanında resim üzerinde kendiniz değişiklik yapıyorsanız bunları nodpi yapılandırma niteleyicisiyle bir dizine yerleştirin). Bu niteleyiciye sahip kaynaklar yoğunluktan bağımsız olarak kabul edilir ve sistem bunları ölçeklendirmez.

Diğer yapılandırma niteleyicileri ve Android'in geçerli ekran yapılandırması için uygun kaynakları nasıl seçtiği hakkında daha fazla bilgi için Uygulama kaynaklarına genel bakış bölümüne bakın.

Uygulama simgelerini mipmap dizinlerine yerleştir

Diğer bit eşlem öğelerinde olduğu gibi, uygulama simgenizin yoğunluğa özel sürümlerini sağlamanız gerekir. Ancak bazı uygulama başlatıcılar, uygulama simgenizi cihazın yoğunluk paketinde belirtilenden %25 daha büyük olarak gösterir.

Örneğin, bir cihazın yoğunluk paketi xxhdpi ise ve sağladığınız en büyük uygulama simgesi drawable-xxhdpi içindeyse uygulama başlatıcı bu simgenin ölçeğini büyüterek daha net bir görünüme sahip değildir.

Bunu önlemek için tüm uygulama simgelerinizi drawable dizin yerine mipmap dizinine yerleştirin. drawable dizinlerinin aksine, yoğunluğa özel APK'lar oluştursanız bile mipmap dizinlerinin tümü APK'da tutulur. Bu şekilde başlatıcı uygulamalar ana ekranda görüntülenecek en iyi çözünürlük simgesini seçebilir.

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

Önceki xxhdpi cihaz örneğinde, mipmap-xxxhdpi dizininde daha yüksek yoğunluklu başlatıcı simgesi sağlayabilirsiniz.

Simge tasarımıyla ilgili yönergeler için Sistem simgeleri konusuna bakın.

Uygulama simgeleri oluşturma konusunda yardım için Image Asset Studio ile uygulama simgeleri oluşturma konusuna bakın.

Yaygın olmayan yoğunluk sorunları için öneri

Bu bölümde, Android'in farklı piksel yoğunluklarında bit eşlemler için nasıl ölçeklendirme yaptığı ve bit eşlemlerin farklı yoğunluklarda çizilme şeklini nasıl daha iyi kontrol edebileceğiniz açıklanmaktadır. Uygulamanız grafikleri değiştirmiyorsa veya farklı piksel yoğunluklarında çalıştırırken sorunlarla karşılaştıysanız bu bölümü yoksayabilirsiniz.

Çalışma zamanında grafikleri değiştirirken birden fazla yoğunluğu nasıl destekleyebileceğinizi daha iyi anlamak için sistemin bit eşlemler için doğru ölçeği sağlamaya nasıl yardımcı olduğunu bilmeniz gerekir. Bu, aşağıdaki şekillerde yapılır:

  1. Bit eşlem çekilebilir kaynakları gibi kaynakların önceden ölçeklendirilmesi

    Mevcut ekranın yoğunluğuna bağlı olarak sistem, uygulamanızdaki yoğunluğa özel tüm kaynakları kullanır. Kaynaklar doğru yoğunlukta mevcut değilse sistem, varsayılan kaynakları yükler ve gerektiğinde bunları yukarı veya aşağı ölçeklendirir. Sistem, varsayılan kaynakların (yapılandırma niteleyicileri olmayan bir dizinden gelenler) referans piksel yoğunluğuna (mdpi) göre tasarlandığını varsayar ve bu bit eşlemleri, geçerli piksel yoğunluğuna uygun boyuta yeniden boyutlandırır.

    Önceden ölçeklenmiş bir kaynağın boyutlarını talep ederseniz sistem, ölçeklendirmeden sonra boyutları temsil eden değerleri döndürür. Örneğin, bir mdpi ekranı için 50x50 piksel olarak tasarlanmış bir bit eşlem, hdpi ekranda 75x75 piksele ölçeklendirilir (hdpi için alternatif bir kaynak yoksa) ve sistem, boyutu bu şekilde bildirir.

    Android'in bir kaynağı önceden ölçeklendirmesini istemeyebileceğiniz durumlar vardır. Ön ölçeklendirmeyi önlemenin en kolay yolu, kaynağı nodpi yapılandırma niteleyicisi ile bir kaynak dizinine yerleştirmektir. Örneğin:

    res/drawable-nodpi/icon.png

    Sistem bu klasördeki icon.png bit eşlemesini kullandığında, dosyayı geçerli cihaz yoğunluğuna göre ölçeklendirmez.

  2. Piksel boyutlarını ve koordinatlarını otomatik ölçeklendirme

    Ölçeklendirme öncesi boyutları ve resimleri, manifest dosyasında android:anyDensity değerini "false" olarak ayarlayarak veya bir Bitmap için programatik olarak inScaled değerini "false" olarak ayarlayıp, programatik olarak devre dışı bırakabilirsiniz. Bu durumda sistem, çizim sırasında mutlak piksel koordinatlarını ve piksel boyutu değerlerini otomatik olarak ölçeklendirir. Bunu, piksel tanımlı ekran öğelerinin, referans piksel yoğunluğunda (mdpi) görüntülenebilecekleri yaklaşık olarak aynı fiziksel boyutta görüntülenmesini sağlamak için yapılır. Sistem, bu ölçeklendirmeyi şeffaf bir şekilde uygulamaya uygular ve ölçeklendirilmiş piksel boyutlarını uygulamaya fiziksel piksel boyutları yerine raporlar.

    Örneğin, bir cihazın, 480x800 boyutunda ve geleneksel bir HVGA ekranıyla hemen hemen aynı boyutta bir WVGA yüksek yoğunluklu ekranına sahip olduğunu, ancak ön ölçeklendirmeyi devre dışı bırakan bir uygulama çalıştırdığını varsayalım. Bu durumda, sistem ekran boyutlarını sorgularken ve piksel yoğunluğu için yaklaşık mdpi çevirisi olan 320x533 değerini bildirdiğinde uygulamaya "bağlanır".

    Daha sonra uygulama, çizim işlemlerini tamamladığında (10,10 ile (100,100) arasındaki bir dikdörtgeni geçersiz kılmak gibi) sistem, koordinatları uygun miktarda ölçeklendirerek dönüştürür ve ardından bölgeyi (15,15) değerini (150, 150) geçersiz kılar. Uygulamanız ölçeklendirilen bit eşlemeyi doğrudan değiştirirse bu tutarsızlık beklenmedik davranışa neden olabilir, ancak bu, mümkün olan en iyi uygulama performansını sağlamak için makul bir deneyim olarak kabul edilir. Bu durumla karşılaşırsanız Dp birimlerini piksel birimlerine dönüştürme bölümünü okuyun.

    Genellikle ön ölçeklendirmeyi devre dışı bırakmazsınız. Birden fazla ekranı desteklemenin en iyi yolu, bu sayfada açıklanan temel teknikleri uygulamaktır.

Uygulamanız bit eşlemleri değiştiriyorsa veya ekrandaki piksellerle başka bir şekilde doğrudan etkileşimde bulunuyorsa farklı piksel yoğunluklarını desteklemek için ek adımlar uygulamanız gerekebilir. Örneğin, dokunma hareketlerine bir parmağın geçtiği piksel sayısını sayarak yanıt verirseniz gerçek piksel yerine uygun yoğunluktan bağımsız piksel değerlerini kullanmanız gerekir, ancak dp ve px değerleri arasında dönüşüm yapabilirsiniz.

Tüm piksel yoğunluklarını test et

Uygulamanızı farklı piksel yoğunluklarına sahip birden fazla cihazda test ederek kullanıcı arayüzünüzün doğru ölçeklendirildiğinden emin olun. Mümkün olduğunda bir fiziksel cihazda test edin; farklı piksel yoğunluklarının tamamı için fiziksel cihazlara erişiminiz yoksa Android Emülatör'ü kullanın.

Fiziksel cihazlarda test yapmak istiyor ancak cihazları satın almak istemiyorsanız bir Google veri merkezindeki cihazlara erişmek için Firebase Test Lab'i kullanabilirsiniz.