Esnek widget düzenleri sağlama

Bu sayfada, Android 12'de (API düzeyi 31) kullanıma sunulan widget boyutu hassaslaştırmaları ve daha fazla esneklik açıklanmaktadır. Ayrıca, widget'ınız için nasıl boyut belirleyeceğiniz de açıklanmaktadır.

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

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

  1. Ek widget boyutu sınırlamaları belirtin.

  2. Duyarlı düzenler veya tam düzenler sağlayın.

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 bir 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 çalışmaz. 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 sınırlamaları belirtme

Android 12'ye eklenen API'ler, widget'ınızın farklı ekran boyutlarına sahip farklı cihazlarda daha güvenilir bir şekilde boyutlandırılmasını sağlar.

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

  • targetCellWidth ve targetCellHeight: Başlatıcı ızgara hücreleri açısından widget'ın hedef boyutunu tanımlayın. Tanımlanmışsa bu özellikler 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ımlayın.

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

Düzenin widget'ın boyutuna bağlı olarak değişmesi gerekiyorsa her biri farklı 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üzenler sağlamaktır.

Bu özellik, widget'ı her görüntülediğinde sistemin uygulamayı uyandırması gerekmez ve widget'ı farklı bir boyutta görüntülemek zorunda kalmaz. Böylece daha sorunsuz ölçeklendirme yapabilir ve sistemin genel olarak daha sağlıklı durumda olmasını sağlar.

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 anlamlara gelir:

  • smallView, 160 dp (minResizeWidth) × 110 dp (minResizeHeight) ile 160 dp × 199 dp (sonraki kesme noktası - 1 dp) arasında bir alanı destekler.
  • tallView, 160 dp × 200 dp ile 214 dp (sonraki kesim noktası - 1) × 200 dp aralığında desteklenir.
  • wideView, 215 dp × 110 dp (minResizeHeight) ile 250 dp (maxResizeWidth) × 200 dp (maxResizeHeight) arasında desteklenir.

Widget'ınız minResizeWidth × minResizeHeight - maxResizeWidth × maxResizeHeight arasındaki boyut aralığını desteklemelidir. Bu aralıkta, düzenleri değiştirmek için kesme 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 uyarlanmış farklı düzenler sağlayabilirsiniz. Bu boyut, telefonlar için genellikle iki boyut (dikey ve yatay mod) ve katlanabilir cihazlar için dört boyuttur.

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

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

  2. AppWidgetManager.getAppWidgetOptions() işlevini çağırın. Bu çağrı, boyutları içeren bir Bundle döndürür.

  3. AppWidgetManager.OPTION_APPWIDGET_SIZES anahtarına Bundle üzerinden 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 tüm Android sürümleri için varsayılan olarak tükettiği minimum alanı belirtecek şekilde minWidth ve minHeight tanımlamalıdır. Ancak kullanıcılar ana ekranlarına bir widget eklediklerinde, bu widget genellikle belirttiğiniz minimum genişlik ve yükseklikten daha fazla yer kaplar.

Android ana ekranları, kullanıcılara widget'ları ve simgeleri yerleştirebilecekleri boş bir alan sunar. Bu ızgara cihaza göre değişebilir; örneğin, birçok mobil cihazda 5x4, tabletler ise daha büyük bir ızgara sunar. Widget'ınız eklendiğinde, Android 12 veya sonraki sürümleri çalıştıran cihazlarda targetCellWidth ve targetCellHeight ya da Android 11 (API düzeyi 30) veya daha düşük sürümleri çalıştıran cihazlarda minWidth ve minHeight kısıtlamalarını karşılamak için yatay ve dikey olarak minimum hücre sayısını kaplayacak şekilde uzatılır.

Hem hücrenin genişliği hem de yüksekliği ve widget'lara uygulanan otomatik kenar boşluklarının boyutu, cihazlar arasında farklılık gösterebilir. İstediğiniz dolu ızgara hücresi sayısına göre tipik bir 5x4 ızgara 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 d (73n - 16) x (118m - 16) (142n - 15) x (66m - 15)

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

Bunun nedeni, hücre genişliğinin dikey modda genellikle yatay moddan daha küçük olması ve benzer şekilde, hücre yüksekliğinin yatay modda dikey modda olduğundan genellikle 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, dikey olarak en az 57 dp genişliğinde olduğundan minResizeWidth özelliğinin değerinin 57 dp'den küçük olduğundan emin olmak için minResizeWidth değerini en fazla 56 dp'ye ayarlamanız gerekir. Benzer şekilde, widget yüksekliğinizin aynı cihazda tek bir hücrede yeniden boyutlandırılabilmesini istiyorsanız minResizeHeight özelliğinin değerinin 51 dp'den küçük olduğundan emin olmak için minResizeHeight değerini en fazla 50 dp olacak şekilde ayarlamanız gerekir. Bunun nedeni, yatay modda bir hücrenin en az 51 dp yüksekliğidir.

Her widget, minResizeWidth/minResizeHeight ve maxResizeWidth/maxResizeHeight özellikleri arasındaki boyut aralıkları içinde yeniden boyutlandırılabilir. Diğer bir deyişle, widget'ların aralarındaki tüm boyut aralıklarına uyarlanması gerekir.

Örneğin, yerleşimdeki 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 özelliklerinde belirtildiği gibi 3x2 hücreler veya Android 11 veya önceki sürümleri çalıştıran cihazlar için minWidth ve minHeight tarafından belirtildiği üzere 180×110 dp olduğu anlamına gelir. İkinci durumda, hücrelerdeki boyut cihaza bağlı olarak değişebilir.

Ayrıca, 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 kadar, yüksekliği ise 110 dp ile 450 dp arasında yeniden boyutlandırılabilir. Bu durumda widget, aşağıdaki koşullar mevcut olduğu sürece 3x2'den 5x2'ye kadar yeniden boyutlandırılabilir:

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. 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) aralığında kullanıldığı anlamına gelir. Benzer şekilde, R.layout.widget_weather_forecast_medium 270x110 dp ile 270x279 dp aralığında, R.layout.widget_weather_forecast_large ise 270x280 dp - 530 dp (maxResizeWidth) x 450 dp (maxResizeHeight) aralığı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 boyutundaki örnek hava durumu widget&#39;ı. Kullanıcı arayüzünde konum adı (Tokyo), sıcaklık (14°) ve kısmen bulutlu hava durumu simgesi gösteriliyor.
Şekil 2. 3x2 R.layout.widget_weather_forecast_small.

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

5x2 &quot;orta&quot; boyutunda örnek hava durumu widget&#39;ı. Widget&#39;ın bu şekilde yeniden boyutlandırılması, önceki boyutla aynı kullanıcı arayüzüne sahip olur ancak daha fazla yatay alan kaplayacak şekilde bir hücre uzunluğu kadar uzatılır.
Şekil 4. 5x2 R.layout.widget_weather_forecast_medium.

5x3 &#39;büyük&#39; boyutta örnek hava durumu widget&#39;ı. Widget&#39;ın bu şekilde yeniden boyutlandırılması, önceki widget boyutlarından gelen tüm kullanıcı arayüzünü temel alır ve widget&#39;ın içine Salı ve Çarşamba günlerindeki hava tahminini içeren bir görünüm ekler. Güneşli veya yağmurlu havayı ve her gün için yüksek ve düşük
            sıcaklıkları gösteren simgeler.
Şekil 5. 5x3 R.layout.widget_weather_forecast_large.

5x4 &#39;büyük&#39; boyutta örnek hava durumu widget&#39;ı. Widget&#39;ın bu şekilde yeniden boyutlandırılması, önceki widget boyutlarındaki tüm kullanıcı arayüzünü temel alır ve Perşembe ve Cuma günleri (ayrıca her gün için hava durumu ile yüksek ve düşük sıcaklığı belirten karşılık gelen simgeleri) ekler.
Şekil 6. 5x4 R.layout.widget_weather_forecast_large.