Glance ile uygulama widget'ı oluşturma

Aşağıdaki bölümlerde, Glance ile temel bir uygulama widget'ının nasıl oluşturulacağı açıklanmaktadır.

Manifest'te AppWidget bildirme

Kurulum adımlarını tamamladıktan sonra uygulamanızda AppWidget ve meta verilerini tanımlayın.

  1. AppWidget alıcısını GlanceAppWidgetReceiver tarihinden itibaren uzatın:

    class MyAppWidgetReceiver : GlanceAppWidgetReceiver() {
        override val glanceAppWidget: GlanceAppWidget = TODO("Create GlanceAppWidget")
    }

  2. Uygulama widget'ının sağlayıcısını AndroidManifest.xml dosyanıza ve ilişkili meta veri dosyasına kaydedin:

        <receiver android:name=".glance.MyReceiver"
        android:exported="true">
        <intent-filter>
            <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
        </intent-filter>
        <meta-data
            android:name="android.appwidget.provider"
            android:resource="@xml/my_app_widget_info" />
    </receiver>
    

AppWidgetProviderInfo meta verilerini ekleme

Ardından, @xml/my_app_widget_info dosyasında uygulama widget'ı bilgilerini oluşturmak ve tanımlamak için Widget oluşturma kılavuzunu uygulayın.

Glance'teki tek fark, initialLayout XML'nin olmamasıdır ancak bir tane tanımlamanız gerekir. Kitaplıkta sağlanan önceden tanımlanmış yükleme düzenini kullanabilirsiniz:

<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:initialLayout="@layout/glance_default_loading_layout">
</appwidget-provider>

AppWidgetProviderInfo XML'ini bildirme

AppWidgetProviderInfo nesnesi, widget'ınızın temel özelliklerini tanımlar. XML meta veri kaynak dosyanızda (res/xml/my_app_widget_info.xml) AppWidgetProviderInfo öğesini bir <appwidget-provider> öğesi içinde tanımlayın:

<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:minWidth="40dp"
    android:minHeight="40dp"
    android:targetCellWidth="1"
    android:targetCellHeight="1"
    android:maxResizeWidth="250dp"
    android:maxResizeHeight="120dp"
    android:updatePeriodMillis="86400000"
    android:description="@string/example_appwidget_description"
    android:previewLayout="@layout/example_appwidget_preview"
    android:initialLayout="@layout/glance_default_loading_layout"
    android:configure="com.example.android.ExampleAppWidgetConfigurationActivity"
    android:resizeMode="horizontal|vertical"
    android:widgetCategory="home_screen"
    android:widgetFeatures="reconfigurable|configuration_optional">
</appwidget-provider>

Widget boyutlandırma özellikleri

Varsayılan ana ekran, widget'ları penceresinde, tanımlı yüksekliği ve genişliği olan hücrelerden oluşan bir ızgaraya göre konumlandırır. Çoğu ana ekranda widget'lar yalnızca ızgara hücrelerinin tam sayı katları olan boyutlarda (ör. yatay olarak iki hücre, dikey olarak üç hücre) olabilir.

Widget boyutlandırma özellikleri, widget'ınız için varsayılan bir boyut belirtmenize ve widget'ın boyutu için alt ve üst sınırlar belirlemenize olanak tanır. Bu bağlamda, bir widget'ın varsayılan boyutu, ana ekrana ilk eklendiğinde aldığı boyuttur.

Aşağıdaki tabloda, widget boyutlandırmayla ilgili <appwidget-provider> özellikleri açıklanmaktadır:

Özellikler ve açıklama
targetCellWidth ve targetCellHeight (Android 12), minWidth ve minHeight
  • Android 12'den itibaren targetCellWidth ve targetCellHeight özellikleri, widget'ın varsayılan boyutunu ızgara hücreleri cinsinden belirtir. Bu özellikler Android 11 ve önceki sürümlerde yoksayılır. Ana ekran, ızgara tabanlı bir düzeni desteklemiyorsa yoksayılabilir.
  • minWidth ve minHeight özellikleri, widget'ın dp cinsinden varsayılan boyutunu belirtir. Bir widget'ın minimum genişlik veya yükseklik değerleri hücrelerin boyutlarıyla eşleşmiyorsa değerler en yakın hücre boyutuna yuvarlanır.
Kullanıcının cihazı targetCellWidth ve targetCellHeight özelliklerini desteklemiyorsa uygulamanızın minWidth ve minHeight özelliklerini kullanabilmesi için her iki özellik grubunu da (targetCellWidth ve targetCellHeight ile minWidth ve minHeight) belirtmenizi öneririz. Destekleniyorsa targetCellWidth ve targetCellHeight özellikleri, minWidth ve minHeight özelliklerine göre öncelikli olur.
minResizeWidth ve minResizeHeight Widget'ın mutlak minimum boyutunu belirtin. Bu değerler, widget'ın okunamayacak veya kullanılamayacak kadar küçük olduğu boyutu belirtir. Bu özellikleri kullanmak, kullanıcının widget'ı varsayılan widget boyutundan daha küçük bir boyuta yeniden boyutlandırmasına olanak tanır. minResizeWidth özelliği, minWidth değerinden büyükse veya yatay yeniden boyutlandırma etkinleştirilmemişse yoksayılır. resizeMode sayfasına göz atın. Benzer şekilde, minResizeHeight özelliği minHeight değerinden büyükse veya dikey yeniden boyutlandırma etkinleştirilmemişse yoksayılır.
maxResizeWidth ve maxResizeHeight Widget'ın önerilen maksimum boyutunu belirtin. Değerler, ızgara hücresi boyutlarının katı değilse en yakın hücre boyutuna yuvarlanır. maxResizeWidth özelliği, minWidth değerinden küçükse veya yatay yeniden boyutlandırma etkinleştirilmemişse yoksayılır. resizeMode sayfasına göz atabilirsiniz. Benzer şekilde, maxResizeHeight özelliği minHeight özelliğinden küçükse veya dikey yeniden boyutlandırma etkinleştirilmemişse yoksayılır. Android 12'de kullanıma sunulmuştur.
resizeMode Bir widget'ın yeniden boyutlandırılabileceği kuralları belirtir. Bu özelliği, ana ekran widget'larını yatay, dikey veya her iki eksende yeniden boyutlandırılabilir hale getirmek için kullanabilirsiniz. Kullanıcılar bir widget'a dokunup basılı tutarak yeniden boyutlandırma tutma yerlerini gösterir, ardından yatay veya dikey tutma yerlerini sürükleyerek düzen ızgarasındaki boyutunu değiştirir. resizeMode özelliğinin değerleri arasında horizontal, vertical ve none yer alır. Bir widget'ın yatay ve dikey olarak yeniden boyutlandırılabileceğini belirtmek için horizontal|vertical kullanın.

Örnek

Yukarıdaki tablodaki özelliklerin widget boyutlandırmayı nasıl etkilediğini göstermek için aşağıdaki özellikleri varsayalım:

  • Izgara hücresi 30 dp genişliğinde ve 50 dp yüksekliğindedir.
  • Aşağıdaki özellik spesifikasyonu sağlanır:
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:minWidth="80dp"
    android:minHeight="80dp"
    android:targetCellWidth="2"
    android:targetCellHeight="2"
    android:minResizeWidth="40dp"
    android:minResizeHeight="40dp"
    android:maxResizeWidth="120dp"
    android:maxResizeHeight="120dp"
    android:resizeMode="horizontal|vertical" />

Android 12'den itibaren:

Widget'ın varsayılan boyutu olarak targetCellWidth ve targetCellHeight özelliklerini kullanın.

Widget'ın boyutu varsayılan olarak 2x2'dir. Widget'ın boyutu 2x1'e kadar küçültülebilir veya 4x3'e kadar büyütülebilir.

Android 11 ve önceki sürümler:

Widget'ın varsayılan boyutunu hesaplamak için minWidth ve minHeight özelliklerini kullanın.

Varsayılan genişlik = Math.ceil(80 / 30) = 3

Varsayılan yükseklik = Math.ceil(80 / 50) = 2

Widget'ın boyutu varsayılan olarak 3x2'dir. Widget'ı 2x1 boyutuna kadar küçültebilir veya tam ekran boyutuna kadar büyütebilirsiniz.

Ek widget özellikleri

Aşağıdaki tabloda, widget boyutlandırma dışındaki niteliklerle ilgili <appwidget-provider> özellikleri açıklanmaktadır.

Özellikler ve açıklama
updatePeriodMillis Widget çerçevesinin, onUpdate() geri çağırma yöntemini çağırarak GlanceAppWidgetReceiver öğesinden ne sıklıkta güncelleme isteyeceğini tanımlar. Pilden tasarruf etmek için mümkün olduğunca seyrek (saatte en fazla bir kez) güncelleme yapmanızı öneririz. Ayrıntılar için Glance durum yönetimi bölümündeki Widget'lar ne zaman güncellenir? bölümüne bakın.
initialLayout Glance kullanıcı arayüzü bileşenleri oluşturulmadan önce widget'ın yükleme düzenini tanımlayan düzen kaynağını gösterir. Kitaplıkta sunulan önceden tanımlanmış yükleme düzenini kullanabilirsiniz: @layout/glance_default_loading_layout.
configure Kullanıcı widget'ı eklediğinde başlatılan yapılandırma etkinliğini tanımlar. Kullanıcıların uygulama widget'larını yapılandırmasına izin verme kılavuzunu inceleyin.
description Widget seçicinin widget'ınız için göstereceği açıklamayı belirtir. Android 12'de kullanıma sunulmuştur.
previewLayout (Android 12) ve previewImage (Android 11 ve önceki sürümler)
  • Android 12'den itibaren previewLayout özelliği, widget'ın varsayılan boyutuna ayarlanmış bir XML düzeni olarak sağladığınız ölçeklenebilir bir önizleme belirtir. İdeal olarak bu, tasarım düzeninizle eşleşen statik bir XML eşlemesine işaret eder.
  • Android 11 veya önceki sürümlerde previewImage özelliği, widget'ın nasıl göründüğünü gösteren statik bir resim çizilebilir ekran görüntüsünü belirtir ve widget seçicide görünür.
Uygulamanızın eski platformlarda sorunsuz bir şekilde çalışması için her ikisini de belirtmenizi öneririz. Daha yeni platformlarda (Android 15 ve sonraki sürümler) `GlanceAppWidget.providePreview` kullanarak Kotlin'de canlı olarak oluşturulan önizlemeler tanımlayabilirsiniz. Oluşturulan önizlemeler kılavuzuna bakın.
autoAdvanceViewId Widget'ın ana makinesi tarafından otomatik olarak ilerletilen widget alt görünümünün görünüm kimliğini belirtir.
widgetCategory Widget'ınızın ana ekranda (home_screen), kilit ekranında (keyguard) veya her ikisinde gösterilip gösterilemeyeceğini belirtir. Android 5.0 ve sonraki sürümler için yalnızca home_screen geçerlidir.
widgetFeatures Widget tarafından desteklenen özellikleri bildirir. Örneğin, widget'ınızın yapılandırması isteğe bağlıysa hem configuration_optional hem de reconfigurable değerini belirtin.

GlanceAppWidget kelimesinin tanımı

  1. GlanceAppWidget sınıfını genişleten ve provideGlance yöntemini geçersiz kılan yeni bir sınıf oluşturun. Bu yöntem, widget'ınızı oluşturmak için gereken verileri yükleyebileceğiniz yöntemdir:

    class MyAppWidget : GlanceAppWidget() {
    
        override suspend fun provideGlance(context: Context, id: GlanceId) {
    
            // In this method, load data needed to render the AppWidget.
            // Use `withContext` to switch to another thread for long running
            // operations.
    
            provideContent {
                // create your AppWidget here
                Text("Hello World")
            }
        }
    }

  2. GlanceAppWidgetReceiver cihazınızdaki glanceAppWidget uygulamasında örneklendirin:

    class MyAppWidgetReceiver : GlanceAppWidgetReceiver() {
    
        // Let MyAppWidgetReceiver know which GlanceAppWidget to use
        override val glanceAppWidget: GlanceAppWidget = MyAppWidget()
    }

Glance'i kullanarak bir AppWidget yapılandırdınız.

Farklı boyut gruplarında widget resim belleğini yönetme

Widget'ınız bitmap'leri veya content:// resim URI'lerini gösterdiğinde, toplam serileştirilmiş RemoteViews resim belleğini sistem sınırında (6 * width * height bayt, Android 17 ve sonraki sürümlerde IllegalArgumentException ile zorunlu kılınır) tutmak için aşağıdakileri yapın:

  • provideContent öncesinde paylaşılan bitmap'lerin kodunu çözme: Widget'ınız SizeMode.Responsive veya SizeMode.Exact kullanıyorsa Glance, her DpSize grubu için provideContent lambda'yı bir kez çalıştırır. provideContent içinde bir Bitmap kodunu çözmek, her paket için ayrı bir Bitmap örneği ayırarak RemoteViews.mBitmapCache içindeki bellek kullanımını artırır. Tüm grupların tek bir Bitmap referansını paylaşması için provideContent işleminden önce provideGlance içinde bir kez alt örneklenmiş bit eşlemlerin (opak resimler için Bitmap.Config.RGB_565) kodunu çözün.
  • Eşleşen ImageProvider içe aktarma işlemini kullanın: Jetpack Glance, iki paket genelinde iki farklı ImageProvider aşırı yükleme sağlar:

    • Bellek içi ImageProvider(bitmap: Bitmap) veya drawable kaynak ImageProvider(resId: Int) iletirken import androidx.glance.ImageProvider kullanın.
    • URI iletirken import androidx.glance.appwidget.ImageProvider kullanın ImageProvider(uri: Uri). Önbelleğe alınmış dosyaları bir FileProvider URI'si üzerinden sunarken ana makinenin resmi oluşturabilmesi için yüklü her Intent.CATEGORY_HOME başlatıcı paketine Intent.FLAG_GRANT_READ_URI_PERMISSION izni verin.

Widget yayınlarını işlemek için GlanceAppWidgetReceiver sınıfını kullanma

GlanceAppWidgetReceiver, temel AppWidgetProvider'yi genişleterek widget yayınlarını ve platform durumu güncellemelerini koordine eder. Widget'ınız güncellendiğinde, silindiğinde, etkinleştirildiğinde veya devre dışı bırakıldığında platform etkinliklerini alır ve bunları Compose yaşam döngüsü isteklerine dönüştürür.

Manifest dosyasında widget tanımlama

GlanceAppWidgetReceiver sınıfı alt sınıfınızı AndroidManifest.xml dosyanızda yayın alıcısı olarak tanımlayın:

<receiver android:name="MyReceiver"
          android:exported="false">
    <intent-filter>
        <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
    </intent-filter>
    <meta-data android:name="android.appwidget.provider"
               android:resource="@xml/my_app_widget_info" />
</receiver>

<receiver> öğesi, alıcı sınıfını belirten android:name özelliğini gerektirir. Alıcı, <intent-filter> içindeki ACTION_APPWIDGET_UPDATE yayın işlemini kabul etmelidir.

<meta-data> öğesi, adını android.appwidget.provider olarak tanımlamalı ve android:resource özelliği, AppWidgetProviderInfo XML meta veri kaynağınızı (@xml/my_app_widget_info) işaret etmelidir.

GlanceAppWidgetReceiver sınıfını uygulama

Glance'te doğrudan AppWidgetProvider yerine GlanceAppWidgetReceiver sınıfını genişletirsiniz. Alıcınızı GlanceAppWidget örneğinize bağlayarak uygulayın. GlanceAppWidgetReceiver içinde kullanılabilen birincil geri çağırmalar aşağıdaki gibi çalışır:

  • onUpdate(): Oluşturma güncellemelerini yürütmek için Glance tarafından otomatik olarak geçersiz kılınır. onUpdate değerini manuel olarak geçersiz kılarsanız Glance'in oluşturma iş parçacıklarını başarıyla başlatmasına izin vermek için super.onUpdate yöntemini çağırmanız gerekir.
  • onAppWidgetOptionsChanged(): Widget ilk kez yerleştirildiğinde veya yeniden boyutlandırıldığında çağrılır. Glance, okuma seçenekleri paket öğelerini arka planda gruplandırır. Böylece düzeniniz, çalışma zamanı boyutlarına göre sorunsuz bir şekilde ayarlanır.
  • onDeleted(Context, IntArray): Belirli bir widget örneği kullanıcı tarafından silindiğinde çağrılır.
  • onEnabled(Context): Widget'ınızın ilk örneği başarıyla oluşturulduğunda tetiklenir. Global taşıma işlemleri için mükemmeldir.
  • onDisabled(Context): Sağlayıcının son etkin örneği kaldırıldığında çağrılır.
  • onReceive(Context, Intent): Belirli geri çağırma yöntemlerinden önce her platform yayınını engeller. Yazdığınız tüm özel alıcı mantıklarının super.onReceive(context, intent) yöntemini çağırdığından emin olmanız gerekir. Glance, işleri otomatik olarak eşzamansız şekilde yönlendirdiğinden goAsync yöntemini hiçbir zaman kendiniz çağırmamalısınız.

Widget yayın amaçlarını alma

GlanceAppWidgetReceiver, arka planda aşağıdaki temel platform widget'ı yayın intent'lerini filtreler ve işler:

Kullanıcı arayüzü oluşturma

Aşağıdaki snippet'te kullanıcı arayüzünün nasıl oluşturulacağı gösterilmektedir:

/* Import Glance Composables
 In the event there is a name clash with the Compose classes of the same name,
 you may rename the imports per https://kotlinlang.org/docs/packages.html#imports
 using the `as` keyword.

import androidx.glance.Button
import androidx.glance.layout.Column
import androidx.glance.layout.Row
import androidx.glance.text.Text
*/
class MyAppWidget : GlanceAppWidget() {

    override suspend fun provideGlance(context: Context, id: GlanceId) {
        // Load data needed to render the AppWidget.
        // Use `withContext` to switch to another thread for long running
        // operations.

        provideContent {
            // create your AppWidget here
            MyContent()
        }
    }

    @Composable
    private fun MyContent() {
        Column(
            modifier = GlanceModifier.fillMaxSize(),
            verticalAlignment = Alignment.Top,
            horizontalAlignment = Alignment.CenterHorizontally
        ) {
            Text(text = "Where to?", modifier = GlanceModifier.padding(12.dp))
            Row(horizontalAlignment = Alignment.CenterHorizontally) {
                Button(
                    text = "Home",
                    onClick = actionStartActivity<MyActivity>()
                )
                Button(
                    text = "Work",
                    onClick = actionStartActivity<MyActivity>()
                )
            }
        }
    }
}

Yukarıdaki kod örneği şunları yapar:

  • Üst düzeyde Column, öğeler dikey olarak birbiri ardına yerleştirilir.
  • Column, boyutunu kullanılabilir alana uyacak şekilde genişletir (GlanceModifier aracılığıyla) ve içeriğini en üste (verticalAlignment) hizalayıp yatay olarak ortalar (horizontalAlignment).
  • Column içeriği, lambda kullanılarak tanımlanır. Sıralama önemlidir.
    • Column içindeki ilk öğe, 12.dp dolgulu bir Text bileşenidir.
    • İkinci öğe, öğelerin yatay olarak birbiri ardına yerleştirildiği ve iki Buttons öğesinin yatay olarak ortalandığı (horizontalAlignment) bir Row öğesidir. Son görüntü, kullanılabilir alana bağlıdır. Aşağıdaki resimde, bunun nasıl görünebileceğine dair bir örnek verilmiştir:
destination_widget
Şekil 1. Örnek kullanıcı arayüzü.

Bileşenlerin yerleşimini ve boyutunu değiştirmek için hizalama değerlerini değiştirebilir veya farklı değiştirici değerleri (ör. dolgu) uygulayabilirsiniz. Bileşenlerin, parametrelerin ve her sınıf için kullanılabilir değiştiricilerin tam listesi için referans belgelerine bakın.

Yuvarlatılmış köşeler kullanma

Android 12, uygulama widget'larınızın köşe yarıçaplarını dinamik olarak özelleştirmek için sistem parametreleri sunar:

  • system_app_widget_background_radius: Widget arka plan kapsayıcısının köşe yarıçapını belirtir (hiçbir zaman 28 dp'den büyük olamaz).
  • İç yarıçap: İçeriğin kırpılmasını önlemek için sistem arka plan ana hattına göre iç içeriğiniz için orantılı bir yarıçap hesaplayın: systemRadiusValue - widgetPadding

Glance'te, GlanceModifier.cornerRadius(android.R.dimen.system_app_widget_background_radius) kullanarak köşe yarıçapı boyutlandırma özelliklerini oluşturma sırasında dinamik olarak uygulayabilirsiniz.

Android 11 (API düzeyi 30) veya daha eski sürümleri çalıştıran cihazlarda geriye dönük uyumluluk için özel özellikleri ve özel tema kaynağı yedeklerini uygulayın:

  • /values/attrs.xml

    <resources>
    <attr name="backgroundRadius" format="dimension" />
    </resources>
    
  • /values/styles.xml

    <resources>
    <style name="MyWidgetTheme">
      <item name="backgroundRadius">@dimen/my_background_radius_dimen</item>
    </style>
    </resources>
    
  • /values-31/styles.xml

    <resources>
    <style name="MyWidgetTheme" parent="@android:style/Theme.DeviceDefault.DayNight">
      <item name="backgroundRadius">@android:dimen/system_app_widget_background_radius</item>
    </style>
    </resources>
    
  • /drawable/my_widget_background.xml

    <shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <corners android:radius="?attr/backgroundRadius" />
    </shape>