Esnek widget düzenleri sağlama

Bu sayfada, Android 12'de (API düzeyi 31) sunulan widget boyutlandırması ve daha fazla esneklikle ilgili iyileştirmeler açıklanmaktadır. Ayrıca, Widget'ınız için boyut belirleme konusunda da ayrıntılı bilgi verilmektedir.

Widget boyutları ve düzenleri için iyileştirilmiş API'ler kullanın

Android 12 (API düzeyi 31) sürümünden itibaren, aşağıdaki bölümlerde açıklandığı şekilde aşağıdakileri yaparak daha hassas boyut özellikleri ve esnek düzenler sağlayabilirsiniz:

  1. Ek widget boyutlandırma kısıtlamaları belirleme

  2. Duyarlı düzenler veya tam düzenler sağlama.

Android'in önceki sürümlerinde OPTION_APPWIDGET_MIN_WIDTH, OPTION_APPWIDGET_MIN_HEIGHT, OPTION_APPWIDGET_MAX_WIDTH ve OPTION_APPWIDGET_MAX_HEIGHT ekstralarını kullanarak widget'ın boyut aralıklarını almak ve ardından widget'ın boyutunu tahmin etmek mümkündür, ancak bu mantık her durumda işe yaramaz. Android 12 veya sonraki sürümleri hedefleyen widget'lar için duyarlı veya tam düzenler sağlamanızı öneririz.

Ek widget boyutu kısıtlamaları belirleme

Android 12'de, widget'ınızın çeşitli ekran boyutlarına sahip farklı cihazlarda daha güvenilir şekilde boyutlandırılmasını sağlayan API'ler bulunur.

Mevcut minWidth, minHeight, minResizeWidth ve minResizeHeight özelliklerine ek olarak aşağıdaki yeni appwidget-provider özelliklerini kullanın:

  • targetCellWidth ve targetCellHeight: Widget'ın hedef boyutunu, başlatıcı ızgara hücreleri açısından tanımlayın. Bu özellikler tanımlanırsa minWidth veya minHeight yerine kullanılır.

  • maxResizeWidth ve maxResizeHeight: Başlatıcının, kullanıcının widget'ı yeniden boyutlandırmasına izin verdiği maksimum boyutu tanımlar.

Aşağıdaki XML'de, boyutlandırma özelliklerinin nasıl kullanılacağı gösterilmektedir.

<appwidget-provider
  ...
  android:targetCellWidth="3"
  android:targetCellHeight="2"
  android:maxResizeWidth="250dp"
  android:maxResizeHeight="110dp">
</appwidget-provider>

Duyarlı düzenler sağlama

Widget'ın boyutuna bağlı olarak düzenin değişmesi gerekiyorsa her biri çeşitli boyutlar için geçerli olan küçük bir düzen grubu oluşturmanızı öneririz. Bu mümkün değilse bir diğer seçenek de bu sayfada açıklandığı gibi çalışma zamanında tam widget boyutuna göre düzen sağlamaktır.

Bu özellik, widget'ı farklı bir boyutta her görüntülediğinde sistemin uygulamayı uyandırması gerekmediğinden daha sorunsuz ölçeklendirme ve genel olarak daha iyi sistem sağlığına olanak tanır.

Aşağıdaki kod örneğinde, bir düzen listesinin nasıl sağlanacağı gösterilmektedir.

Kotlin

override fun onUpdate(...) {
    val smallView = ...
    val tallView = ...
    val wideView = ...

    val viewMapping: Map<SizeF, RemoteViews> = mapOf(
            SizeF(150f, 100f) to smallView,
            SizeF(150f, 200f) to tallView,
            SizeF(215f, 100f) to wideView
    )
    val remoteViews = RemoteViews(viewMapping)

    appWidgetManager.updateAppWidget(id, remoteViews)
}

Java

@Override
public void onUpdate(...) {
    RemoteViews smallView = ...;
    RemoteViews tallView = ...;
    RemoteViews wideView = ...;

    Map<SizeF, RemoteViews> viewMapping = new ArrayMap<>();
    viewMapping.put(new SizeF(150f, 100f), smallView);
    viewMapping.put(new SizeF(150f, 200f), tallView);
    viewMapping.put(new SizeF(215f, 100f), wideView);
    RemoteViews remoteViews = new RemoteViews(viewMapping);

    appWidgetManager.updateAppWidget(id, remoteViews);
}

Widget'ın aşağıdaki özelliklere sahip olduğunu varsayalım:

<appwidget-provider
    android:minResizeWidth="160dp"
    android:minResizeHeight="110dp"
    android:maxResizeWidth="250dp"
    android:maxResizeHeight="200dp">
</appwidget-provider>

Önceki kod snippet'i şu anlama gelir:

  • smallView; 160 dp (minResizeWidth) × 110 dp (minResizeHeight) ila 160 dp × 199 dp (sonraki son sipariş noktası - 1 dp) boyutlarını destekler.
  • tallView, 160 dp × 200 dp ile 214 dp (sonraki son sipariş noktası - 1) × 200 dp aralığında destekler.
  • wideView, 215 dp × 110 dp (minResizeHeight) ila 250 dp (maxResizeWidth) × 200 dp (maxResizeHeight) boyutlarını destekler.

Widget'ınız minResizeWidth × minResizeHeight ve maxResizeWidth × maxResizeHeight boyut aralığını desteklemelidir. Bu aralık içinde, düzenler arasında geçiş yapmak için kesim noktasına karar verebilirsiniz.

Duyarlı düzen örneği
Şekil 1. Duyarlı düzen örneği.

Tam düzenler sağlayın

Küçük bir duyarlı düzen grubu uygun değilse bunun yerine widget'ın gösterildiği boyutlara göre uyarlanmış farklı düzenler sağlayabilirsiniz. Genellikle telefonlar için iki boyut (dikey ve yatay mod), katlanabilir cihazlar için ise dört boyuttur.

Bu çözümü uygulamak için uygulamanızın aşağıdaki adımları gerçekleştirmesi gerekir:

  1. Aşırı yükleme AppWidgetProvider.onAppWidgetOptionsChanged(), boyut grubu değiştiğinde çağrılır.

  2. AppWidgetManager.getAppWidgetOptions() komutunu çağırarak boyutları içeren bir Bundle döndürür.

  3. AppWidgetManager.OPTION_APPWIDGET_SIZES anahtarına Bundle içinden erişin.

Aşağıdaki kod örneğinde, tam düzenlerin nasıl sağlanacağı gösterilmektedir.

Kotlin

override fun onAppWidgetOptionsChanged(
        context: Context,
        appWidgetManager: AppWidgetManager,
        id: Int,
        newOptions: Bundle?
) {
    super.onAppWidgetOptionsChanged(context, appWidgetManager, id, newOptions)
    // Get the new sizes.
    val sizes = newOptions?.getParcelableArrayList<SizeF>(
            AppWidgetManager.OPTION_APPWIDGET_SIZES
    )
    // Check that the list of sizes is provided by the launcher.
    if (sizes.isNullOrEmpty()) {
        return
    }
    // Map the sizes to the RemoteViews that you want.
    val remoteViews = RemoteViews(sizes.associateWith(::createRemoteViews))
    appWidgetManager.updateAppWidget(id, remoteViews)
}

// Create the RemoteViews for the given size.
private fun createRemoteViews(size: SizeF): RemoteViews { }

Java

@Override
public void onAppWidgetOptionsChanged(
    Context context, AppWidgetManager appWidgetManager, int appWidgetId, Bundle newOptions) {
    super.onAppWidgetOptionsChanged(context, appWidgetManager, appWidgetId, newOptions);
    // Get the new sizes.
    ArrayList<SizeF> sizes =
        newOptions.getParcelableArrayList(AppWidgetManager.OPTION_APPWIDGET_SIZES);
    // Check that the list of sizes is provided by the launcher.
    if (sizes == null || sizes.isEmpty()) {
      return;
    }
    // Map the sizes to the RemoteViews that you want.
    Map<SizeF, RemoteViews> viewMapping = new ArrayMap<>();
    for (SizeF size : sizes) {
        viewMapping.put(size, createRemoteViews(size));
    }
    RemoteViews remoteViews = new RemoteViews(viewMapping);
    appWidgetManager.updateAppWidget(id, remoteViews);
}

// Create the RemoteViews for the given size.
private RemoteViews createRemoteViews(SizeF size) { }

Widget'ınız için boyut belirleme

Her widget, Android 12 veya sonraki sürümleri çalıştıran cihazlar için bir targetCellWidth ve targetCellHeight (ya da Android'in tüm sürümleri için minWidth ve minHeight) tanımlamalı ve varsayılan olarak tükettiği minimum alan miktarını belirtmelidir. Bununla birlikte, kullanıcılar ana ekranlarına bir widget eklediklerinde, widget genellikle belirttiğiniz minimum genişlik ve yükseklikten daha fazla yer kaplar.

Android ana ekranları, kullanıcılara widget ve simgeler yerleştirebilecekleri kullanılabilir alanlar sunar. Bu tablo cihaza göre değişebilir. Örneğin, birçok mobil cihaz 5x4'lük bir ızgaraya sahipken tabletler daha büyük bir ızgara sunabilir. Widget'ınız eklendiğinde, Android 12 veya sonraki sürümleri çalıştıran cihazlarda targetCellWidth ve targetCellHeight kısıtlamalarını ya da Android 11 (API düzeyi 30) veya önceki sürümleri çalıştıran cihazlarda minWidth ve minHeight kısıtlamalarını karşılamak için gereken minimum hücre sayısını yatay ve dikey olarak kaplayacak şekilde genişletilir.

Hücrenin genişliği ve yüksekliği ile widget'lara uygulanan otomatik kenar boşluklarının boyutu cihazlara bağlı olarak farklılık gösterebilir. İstediğiniz dolu ızgara hücresi sayısına göre, tipik bir 5x4 ızgara mobil cihazında widget'ınızın minimum boyutlarını kabaca tahmin etmek için aşağıdaki tabloyu kullanın:

Hücre sayısı (genişlik x yükseklik) Dikey modda kullanılabilir boyut (dp) Yatay modda kullanılabilir boyut (dp)
1x1 57x102dp 127x51dp
2x1 130x102dp 269x51dp
3x1 203x102dp 412x51dp
4x1 276x102dp 554x51dp
5x1 349x102dp 697x51dp
5x2 349x220dp 697x117dp
5x3 349x337dp 697x184dp
5x4 349x455dp 697x250dp
... ... ...
n x m (73n - 16) x (118m - 16) (142 dk - 15) x (66 m - 15)

minWidth, minResizeWidth ve maxResizeWidth özellikleri için sağladığınız değerleri belirtmek amacıyla dikey mod hücre boyutlarını kullanın. Benzer şekilde, minHeight, minResizeHeight ve maxResizeHeight özellikleri için sağladığınız değerleri bildirmek amacıyla yatay mod hücre boyutlarını kullanın.

Bunun nedeni, dikey modda hücre genişliğinin genellikle yatay moda göre daha küçük olmasıdır. Benzer şekilde, yatay modda hücre yüksekliği genellikle dikey moda göre daha küçüktür.

Örneğin, widget genişliğinizin Google Pixel 4'te bir hücre olacak şekilde yeniden boyutlandırılmasını istiyorsanız minResizeWidth özelliğinin değerinin 57 dp'den küçük olması için minResizeWidth ayarınızı en fazla 56 dp olarak ayarlamanız gerekir. Çünkü hücre dikey yönde en az 57 dp genişliğindedir. Benzer şekilde, widget yüksekliğinizin aynı cihazdaki bir hücrede yeniden boyutlandırılabilir olmasını istiyorsanız minResizeHeight özelliğinin değerinin 51 dp'den küçük olması için minResizeHeight ayarınızı en fazla 50 dp olacak şekilde ayarlamanız gerekir. Bunun nedeni, yatay modda bir hücrenin yüksekliği en az 51 dp'dir.

Her widget, minResizeWidth/minResizeHeight ve maxResizeWidth/maxResizeHeight özellikleri arasındaki boyut aralıklarında yeniden boyutlandırılabilir. Diğer bir deyişle, bunların arasındaki tüm boyut aralıklarına uyum sağlaması gerekir.

Örneğin, yerleşimde widget'ın varsayılan boyutunu ayarlamak için aşağıdaki özellikleri ayarlayabilirsiniz:

<appwidget-provider
    android:targetCellWidth="3"
    android:targetCellHeight="2"
    android:minWidth="180dp"
    android:minHeight="110dp">
</appwidget-provider>

Bu, widget'ın varsayılan boyutunun targetCellWidth ve targetCellHeight özellikleriyle belirtilen 3x2 hücre veya Android 11 ya da önceki sürümleri çalıştıran cihazlar için minWidth ve minHeight tarafından belirtildiği şekliyle 180×110 dp olduğu anlamına gelir. İkinci durumda, hücrelerdeki boyut cihaza bağlı olarak değişebilir.

Widget'ınızın desteklenen boyut aralıklarını ayarlamak için aşağıdaki özellikleri de ayarlayabilirsiniz:

<appwidget-provider
    android:minResizeWidth="180dp"
    android:minResizeHeight="110dp"
    android:maxResizeWidth="530dp"
    android:maxResizeHeight="450dp">
</appwidget-provider>

Önceki özelliklerde belirtildiği gibi, widget'ın genişliği 180 dp'den 530 dp'ye, yüksekliği ise 110 dp'den 450 dp'ye yeniden boyutlandırılabilir. Daha sonra widget, aşağıdaki koşullar mevcut olduğu sürece 3x2 boyutundan 5x2 hücrelere yeniden boyutlandırılabilir:

  • Cihazda 5x4 ekran görüntüsü var.
  • Hücre sayısı ile kullanılabilir boyut (dps cinsinden) arasındaki eşleme, bu sayfadaki minimum boyutların tahminini gösteren tabloda açıklanmıştır.
  • Widget bu boyut aralığına uyum sağlar.

Kotlin

val smallView = RemoteViews(context.packageName, R.layout.widget_weather_forecast_small)
val mediumView = RemoteViews(context.packageName, R.layout.widget_weather_forecast_medium)
val largeView = RemoteViews(context.packageName, R.layout.widget_weather_forecast_large)

val viewMapping: Map<SizeF, RemoteViews> = mapOf(
        SizeF(180f, 110f) to smallView,
        SizeF(270f, 110f) to mediumView,
        SizeF(270f, 280f) to largeView
)

appWidgetManager.updateAppWidget(appWidgetId, RemoteViews(viewMapping))

Java

RemoteViews smallView = 
    new RemoteViews(context.getPackageName(), R.layout.widget_weather_forecast_small);
RemoteViews mediumView = 
    new RemoteViews(context.getPackageName(), R.layout.widget_weather_forecast_medium);
RemoteViews largeView = 
    new RemoteViews(context.getPackageName(), R.layout.widget_weather_forecast_large);

Map<SizeF, RemoteViews> viewMapping = new ArrayMap<>();
viewMapping.put(new SizeF(180f, 110f), smallView);
viewMapping.put(new SizeF(270f, 110f), mediumView);
viewMapping.put(new SizeF(270f, 280f), largeView);
RemoteViews remoteViews = new RemoteViews(viewMapping);

appWidgetManager.updateAppWidget(id, remoteViews);

Widget'ın, önceki kod snippet'lerinde tanımlanan duyarlı düzenleri kullandığını varsayalım. R.layout.widget_weather_forecast_small olarak belirtilen düzen, 180 dp (minResizeWidth) x 110 dp (minResizeHeight) ile 269x279 dp (sonraki kesim noktaları - 1) arasında kullanılır. Benzer şekilde, 270x110 dp ile 270x279 dp arasında R.layout.widget_weather_forecast_medium, R.layout.widget_weather_forecast_large ise 270x280 dp ile 530 dp (maxResizeWidth) x 450 dp (maxResizeHeight) arasında kullanılır.

Kullanıcı widget'ı yeniden boyutlandırdıkça görünümü, aşağıdaki örneklerde gösterildiği gibi hücrelerdeki her bir boyuta uyum sağlayacak şekilde değişir.

En küçük 3x2 ızgara boyutunda örnek hava durumu widget&#39;ı. Kullanıcı arayüzünde konum adı (Tokyo), sıcaklık (14°) ve havanın kısmen bulutlu olduğunu belirten semboller gösteriliyor.
Şekil 2. 3x2 R.layout.widget_weather_forecast_small.

4x2 &quot;orta&quot; boyutlu örnek hava durumu widget&#39;ı. Widget&#39;ın bu şekilde yeniden boyutlandırılması,
            önceki widget boyutundan kullanıcı arayüzünün tüm kullanıcı arayüzünde yer kaplar,
            &quot;Çoğunlukla bulutlu&quot; etiketini ve
            16:00 ile 19:00 arasındaki sıcaklık tahminini ekler.
Şekil 3. 4x2 R.layout.widget_weather_forecast_medium.

5x2 &quot;orta&quot; boyutlu örnek hava durumu widget&#39;ı. Widget&#39;ı bu şekilde yeniden boyutlandırdığınızda, önceki boyutla aynı kullanıcı arayüzü elde edilir. Tek fark, widget&#39;ın daha fazla yatay alan kaplaması için bir hücre uzunluğunda uzatılmasıdır.
Şekil 4. 5x2 R.layout.widget_weather_forecast_medium.

5x3 &quot;büyük&quot; boyutlu örnek hava durumu widget&#39;ı. Widget&#39;ı bu şekilde yeniden boyutlandırmak,
 önceki widget boyutlarındaki tüm kullanıcı arayüzünü temel alır ve widget&#39;ın içine Salı ve Çarşamba günlerindeki hava durumunun
 tahminini içeren bir görünüm ekler. Her gün için güneşli veya yağmurlu havanın yanı sıra en yüksek ve en düşük sıcaklıkları gösteren semboller.
Şekil 5. 5x3 R.layout.widget_weather_forecast_large.

5x4 &quot;büyük&quot; boyutta örnek hava durumu widget&#39;ı. Widget&#39;ı bu şekilde
 yeniden boyutlandırmak, önceki widget boyutlarındaki tüm kullanıcı arayüzünü temel alır ve
 perşembe ve cuma günlerini (ve bunlara karşılık gelen simgelerle hava durumu türünü
 ve her gün için yüksek ve düşük sıcaklığı belirtir).
Şekil 6. 5x4 R.layout.widget_weather_forecast_large.