Esnek widget düzenleri sağlama

Compose yöntemini deneyin
Jetpack Compose, Android için önerilen kullanıcı arayüzü araç setidir. Compose tarzı API'leri kullanarak widget oluşturmayı öğrenin.

Bu sayfada, Android 12'de (API düzeyi 31) kullanıma sunulan widget boyutlandırma ve daha fazla esneklik ile ilgili iyileştirmeler açıklanmaktadır. Ayrıca, widget'ınızın boyutunu nasıl belirleyeceğiniz de ayrıntılı olarak açıklanmaktadır.

Widget boyutları ve düzenleri için geliştirilmiş API'leri kullanma

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

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

  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 eklerini kullanarak bir widget'ın boyut aralıklarını alıp 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 boyutlandırma kısıtlamaları belirtme

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

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 cinsinden tanımlayın. Tanımlanmışsa minWidth veya minHeight yerine bu özellikler 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, boyutlandırma özelliklerinin nasıl kullanılacağını gösterir.

<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
  android:targetCellWidth="3"
  android:targetCellHeight="2"
  android:maxResizeWidth="250dp"
  android:maxResizeHeight="110dp">
</appwidget-provider>

Duyarlı düzenler sağlama

Düzenin widget'ın boyutuna göre değişmesi gerekiyorsa her biri bir dizi boyut için geçerli olan küçük bir düzen grubu oluşturmanızı öneririz. Bu mümkün değilse başka bir seçenek de bu sayfada açıklandığı gibi çalışma zamanındaki tam widget boyutuna göre düzenler sağlamaktır.

Bu özellik, sistemin widget'ı farklı bir boyutta her gösterdiğinde uygulamayı uyandırması gerekmediğinden daha sorunsuz ölçeklendirme ve genel olarak daha iyi sistem sağlığı sağlar.

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

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

    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)
}

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

<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:minResizeWidth="160dp"
    android:minResizeHeight="110dp"
    android:maxResizeWidth="250dp"
    android:maxResizeHeight="200dp">
</appwidget-provider>

Yukarıdaki kod snippet'i şu anlama gelir:

  • smallView, 160 dp (minResizeWidth) × 110 dp (minResizeHeight) ile 160 dp × 199 dp (sonraki kesme noktası - 1 dp) arasını destekler.
  • tallView, 160 dp × 200 dp ile 214 dp (sonraki kesme noktası - 1) × 200 dp arasındaki boyutları destekler.
  • wideView, 215 dp × 110 dp (minResizeHeight) ile 250 dp (maxResizeWidth) × 200 dp (maxResizeHeight) arasındaki boyutları destekler.

Widget'ınız minResizeWidth × minResizeHeight ile maxResizeWidth × maxResizeHeight arasındaki boyut aralığını desteklemelidir. Bu aralıkta, düzenleri değiştirmek için kesme noktasını belirleyebilirsiniz.

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

Tam düzenleri sağlama

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

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

  1. Boyut grubu değiştiğinde çağrılan aşırı yükleme AppWidgetProvider.onAppWidgetOptionsChanged().

  2. Boyutları içeren bir Bundle döndüren AppWidgetManager.getAppWidgetOptions() yöntemini çağırın.

  3. Bundle üzerinden AppWidgetManager.OPTION_APPWIDGET_SIZES anahtarına erişin.

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

override fun onAppWidgetOptionsChanged(
    context: Context,
    appWidgetManager: AppWidgetManager,
    id: Int,
    newOptions: Bundle?
) {
    super.onAppWidgetOptionsChanged(context, appWidgetManager, id, newOptions)
    // Get the new sizes.
    val sizes = newOptions?.let {
        BundleCompat.getParcelableArrayList(
            it,
            AppWidgetManager.OPTION_APPWIDGET_SIZES,
            SizeF::class.java
        )
    }
    // 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 {
}

Widget'ınız için boyut belirleme

Her widget, Android 12 veya sonraki sürümleri çalıştıran cihazlar için targetCellWidth ve targetCellHeight, tüm Android sürümleri için ise minWidth ve minHeight tanımlayarak varsayılan olarak tükettiği minimum alan miktarını belirtmelidir. Ancak kullanıcılar ana ekranlarına widget eklediğinde widget genellikle belirttiğiniz minimum genişlik ve yükseklikten daha fazla yer kaplar.

Android ana ekranları, kullanıcıların widget ve simge yerleştirebileceği kullanılabilir alanlardan oluşan bir tablo sunar. Bu ızgara, cihaza göre değişiklik gösterebilir. Örneğin, birçok cep telefonu 5x4'lük bir ızgara sunarken 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, Android 11 (API düzeyi 30) veya önceki sürümleri çalıştıran cihazlarda ise 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ücre boyutları ve otomatik kenar boşlukları cihazlara göre farklılık gösterir. İstediğiniz dolu ızgara hücresi sayısına göre, tipik bir 5x4 ızgara telefonunda widget'ınızın minimum boyutlarını 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) (142n - 15) x (66m - 15)

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

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

Örneğin, widget genişliğinizin Google Pixel 4'te bir hücreye kadar yeniden boyutlandırılabilmesini istiyorsanız minResizeWidth özelliğinin değerinin 57 dp'den küçük olduğundan emin olmak için minResizeWidth değerinizi en fazla 56 dp olarak ayarlamanız gerekir. Çünkü bir hücre dikey modda 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 olduğundan emin olmak için minResizeHeight değerinizi en fazla 50 dp olarak ayarlamanız gerekir. Çünkü bir hücre, yatay modda en az 51 dp yüksekliğindedir.

Her widget, minResizeWidth/minResizeHeight ve maxResizeWidth/maxResizeHeight özellikleri arasındaki boyut aralıklarında yeniden boyutlandırılabilir. Bu, widget'ın aralarındaki tüm boyut aralıklarına uyum sağlaması gerektiği anlamına gelir.

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

<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:targetCellWidth="3"
    android:targetCellHeight="2"
    android:minWidth="180dp"
    android:minHeight="110dp">
</appwidget-provider>

Bu, widget'ın varsayılan boyutunun targetCellWidth ve targetCellHeight özellikleri tarafından belirtildiği gibi 3x2 hücre veya Android 11 ya da daha eski sürümleri çalıştıran cihazlar için minWidth ve minHeight tarafından belirtildiği gibi 180x110 dp olduğu anlamına gelir. İkinci durumda, hücre cinsinden boyut cihaza göre değişebilir.

Ayrıca, widget'ınızın desteklenen boyut aralıklarını ayarlamak için aşağıdaki özellikleri ayarlayabilirsiniz:

<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    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. Ardından, aşağıdaki koşullar karşılandığı sürece widget'ın boyutu 3x2 ila 5x2 hücre arasında değiştirilebilir:

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))

Widget'ın, önceki kod snippet'lerinde tanımlanan duyarlı düzenleri kullandığını varsayalım. Bu, R.layout.widget_weather_forecast_small olarak belirtilen düzenin 180 dp (minResizeWidth) x 110 dp (minResizeHeight) ile 269x279 dp (sonraki kesme noktaları - 1) arasında kullanıldığı anlamına gelir. Benzer şekilde, R.layout.widget_weather_forecast_medium 270x110 dp ile 270x279 dp arasında, 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ığında, widget'ın görünümü aşağıdaki örneklerde gösterildiği gibi hücrelerdeki her boyuta uyum sağlayacak şekilde değişir.

En küçük 3x2 ızgara boyutundaki hava durumu widget'ı örneği. Kullanıcı arayüzünde konum adı (Tokyo), sıcaklık (14°) ve parçalı bulutlu havayı gösteren simge yer alıyor.
Şekil 2. 3x2 R.layout.widget_weather_forecast_small.

4x2 &quot;orta&quot; boyutta örnek hava durumu widget'ı. Widget'ı bu şekilde yeniden boyutlandırmak, önceki widget boyutundaki tüm kullanıcı arayüzünü temel alır ve &quot;Çoğunlukla bulutlu&quot; etiketini ve 16:00-19:00 arasındaki sıcaklık tahminini ekler.
Şekil 3. 4x2 R.layout.widget_weather_forecast_medium.

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

5x3 &quot;büyük&quot; boyutunda örnek hava durumu widget'ı. Widget'ı bu şekilde yeniden boyutlandırmak, önceki widget boyutlarındaki tüm kullanıcı arayüzünü temel alır ve widget'ın içine salı ve çarşamba günleri için hava durumu tahminini içeren bir görünüm ekler. Her gün için güneşli veya yağmurlu havayı ve 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'ı. Widget'ı bu şekilde yeniden boyutlandırmak, önceki widget boyutlarındaki tüm kullanıcı arayüzünü temel alır ve perşembe ile cuma günlerini (ve her gün için hava durumunu, en yüksek ve en düşük sıcaklığı gösteren ilgili simgeleri) ekler.
Şekil 6. 5x4 R.layout.widget_weather_forecast_large.