Peningkatan widget Android 12

Android 12 mengubah API Widget yang ada untuk meningkatkan pengalaman pengguna dan developer di platform dan peluncur. Gunakan panduan ini untuk mempelajari cara memastikan widget Anda kompatibel dengan Android 12, dan juga sebagai referensi API untuk memuat ulang widget yang ada.

Teks alternatif

Memastikan widget Anda kompatibel dengan Android 12

Widget di Android 12 memiliki sudut bulat. Saat widget aplikasi digunakan di perangkat yang menjalankan Android 12 atau yang lebih tinggi, peluncur secara otomatis mengidentifikasi latar belakang widget dan memangkasnya agar memiliki sudut bulat.

Dalam skenario ini, widget Anda mungkin tidak akan ditampilkan dengan benar dalam salah satu kondisi berikut:

  • Widget berisi konten di sudut: Hal ini dapat menyebabkan beberapa konten di area sudut terpotong.

  • Widget menggunakan latar belakang yang tidak mudah dipangkas. Ini mencakup latar belakang transparan, tampilan kosong atau tata letak, atau jenis latar belakang khusus lainnya yang tidak rentan dipangkas. Sistem mungkin tidak dapat mengidentifikasi latar belakang yang akan digunakan dengan benar.

Jika widget Anda terpengaruh oleh perubahan ini, sebaiknya refresh widget dengan sudut bulat (seperti yang dijelaskan di bagian berikut) untuk memastikan widget ditampilkan dengan benar.

Menggunakan sampel

Untuk melihat semua API baru ini, lihat widget daftar contoh kami.

Menerapkan sudut bulat

Android 12 memperkenalkan parameter sistem berikut untuk menyetel radius sudut bulat widget Anda:

Contoh berikut menunjukkan widget yang menggunakan system_app_widget_background_radius untuk sudut widget dan system_app_widget_inner_radius untuk tampilan di dalam widget.

Teks alternatif

1 Sudut widget.

2 Sudut tampilan di dalam widget.

Kompatibilitas mundur dengan sudut bulat

Guna memastikan kompatibilitas widget dengan versi Android sebelumnya, untuk Android 12, sebaiknya tentukan atribut kustom dan gunakan tema kustom untuk menggantinya, seperti yang ditunjukkan dalam contoh file XML berikut:

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

/layout/my_widget_layout.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  ...
  android:background="@drawable/my_widget_background" />

Menerapkan warna dinamis

Di Android 12, widget dapat menggunakan warna tema perangkat untuk tombol, latar belakang, dan komponen lainnya. Hal ini memungkinkan transisi dan konsistensi yang lebih lancar di berbagai widget.

Pada contoh berikut, warna tema perangkat "kecoklatan", menyebabkan warna aksen dan latar belakang widget disesuaikan. Anda dapat melakukannya dengan menggunakan tema default sistem (@android:style/Theme.DeviceDefault.DayNight) dan atribut warna. Beberapa atribut warna yang umum digunakan adalah:

  • ?android:attr/colorAccent
  • ?android:attr/colorBackground
  • ?android:attr/textColorPrimary dan ?android:attr/textColorSecondary
Widget dalam tema mode terang
Widget dalam tema terang
Widget dalam tema mode gelap
Widget dengan tema gelap

Kompatibilitas mundur dengan warna dinamis

Sebaiknya Anda membuat tema khusus dan menimpanya untuk Android 12. Contoh berikut menunjukkan cara melakukannya dengan berbagai jenis file XML:

/values/styles.xml

<resources>
  <style name="MyWidget.TextView">
    <item name="android:textColor">@color/my_text_color</item>
  </style>
  <style name="MyWidgetTheme">
    <item name="textViewStyle">@style/MyWidget.TextView</item>
  </style>
</resources>

/values-31/styles.xml

<resources>
  <style name="MyWidgetTheme" parent="Theme.DeviceDefault.DayNight" />
</resources>

/layout/my_widget_layout.xml

<resources>
  <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    ...
    android:theme="@style/MyWidgetTheme" />
</resources>

Mempermudah personalisasi widget

Jika Anda menentukan aktivitas konfigurasi dengan atribut configure dari appwidget-provider, host Widget Aplikasi akan meluncurkan aktivitas tersebut segera setelah pengguna menambahkan widget ke layar utama.

Android 12 menambahkan opsi baru yang memungkinkan Anda memberikan pengalaman konfigurasi yang lebih baik bagi pengguna.

Mengaktifkan pengguna untuk mengonfigurasi ulang widget yang ditempatkan

Untuk mengonfigurasi widget yang dilabeli sebagai dapat dikonfigurasi ulang, pengguna dapat menekan lama widget. Tindakan ini akan menampilkan tombol Konfigurasi ulang, yang dapat diketuk untuk mengubah setelan.

Teks alternatif

1 Tombol konfigurasi ulang.

Tentukan flag reconfigurable dalam atribut widgetFeatures dari appwidget-provider:

<appwidget-provider
  ...
  android:configure="com.myapp.WidgetConfigActivity"
  android:widgetFeatures="reconfigurable">
</appwidget-provider>

Menggunakan konfigurasi default widget

Jika ingin widget menggunakan konfigurasi default saat pengguna menambahkannya, Anda dapat melewati langkah konfigurasi dengan menentukan configuration_optional dan reconfigurable di kolom widgetFeatures. Tindakan ini akan mengabaikan peluncuran aktivitas konfigurasi setelah pengguna menambahkan widget. (Seperti yang disebutkan sebelumnya, pengguna masih dapat mengonfigurasi ulang widget setelahnya.)

Misalnya, widget jam dapat mengabaikan konfigurasi awal dan menampilkan zona waktu perangkat secara default.

<appwidget-provider
  ...
  android:configure="com.myapp.WidgetConfigActivity"
  android:widgetFeatures="reconfigurable|configuration_optional">
</appwidget-provider>

Kompatibilitas mundur dengan opsi konfigurasi widget

Aplikasi Anda dapat menggunakan flag configuration_optional dan reconfigurable di Android versi sebelumnya. Namun, flag ini tidak akan berpengaruh dan sistem masih akan meluncurkan aktivitas konfigurasi.

Menambahkan tombol compound baru

Android 12 menambahkan dukungan baru untuk perilaku status dengan menggunakan komponen yang ada berikut:

Widget tetap stateless. Aplikasi Anda harus menyimpan status dan mendaftar peristiwa perubahan status.

Teks alternatif

Contoh kode berikut menunjukkan cara menerapkan komponen ini.

Kotlin

// Check the view.
remoteView.setCompoundButtonChecked(R.id.my_checkbox, true)

// Check a radio group.
remoteView.setRadioGroupChecked(R.id.my_radio_group, R.id.radio_button_2)

// Listen for check changes. The intent will have an extra with the key
// EXTRA_CHECKED that specifies the current checked state of the view.
remoteView.setOnCheckedChangeResponse(
  R.id.my_checkbox,
  RemoteViews.RemoteResponse.fromPendingIntent(onCheckedChangePendingIntent)
)

Java

// Check the view.
remoteView.setCompoundButtonChecked(R.id.my_checkbox, true);

// Check a radio group.
remoteView.setRadioGroupChecked(R.id.my_radio_group, R.id.radio_button_2);

// Listen for check changes. The intent will have an extra with the key
// EXTRA_CHECKED that specifies the current checked state of the view.
remoteView.setOnCheckedChangeResponse(
  R.id.my_checkbox,
  RemoteViews.RemoteResponse.fromPendingIntent(onCheckedChangePendingIntent)
);

Kompatibilitas mundur dengan tombol compound widget

Sediakan dua tata letak yang berbeda, dengan satu perangkat penargetan yang menjalankan Android 12 atau yang lebih tinggi (res/layout-v31) dan yang lain menargetkan versi Android sebelumnya (di folder res/layout default).

Menggunakan API yang ditingkatkan untuk ukuran dan tata letak widget

Mulai Android 12, Anda dapat memberikan atribut ukuran yang lebih halus dan tata letak yang lebih fleksibel dengan melakukan hal berikut:

  1. Menentukan batasan ukuran widget tambahan

  2. Menyediakan tata letak responsif atau tata letak yang tepat

Menentukan batasan ukuran widget tambahan

Android 12 menambahkan API baru yang memungkinkan Anda memastikan ukuran widget lebih andal di berbagai perangkat dengan berbagai ukuran layar.

Selain minWidth yang ada, minHeight, minResizeWidth, dan minResizeHeight atribut, gunakan atribut baru appwidget-provider berikut:

  • targetCellWidth dan targetCellHeight: Menentukan ukuran target widget dari segi sel petak peluncur. Jika ditentukan, atribut ini digunakan sebagai ganti minWidth atau minHeight.

  • maxResizeWidth dan maxResizeHeight: Menentukan ukuran maksimum peluncur yang memungkinkan pengguna mengubah ukuran widget.

XML berikut menjelaskan cara menggunakan atribut ukuran.

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

Menyediakan tata letak yang responsif

Jika tata letak perlu diubah sesuai ukuran widget, sebaiknya buat set tata letak kecil yang masing-masing valid untuk berbagai ukuran. (Jika tidak memungkinkan, opsi lainnya adalah menyediakan tata letak berdasarkan ukuran widget yang tepat saat waktu proses.)

Penerapan fitur ini memungkinkan penskalaan yang lebih lancar dan kesehatan sistem yang lebih baik secara keseluruhan; hal ini karena sistem tidak harus mengaktifkan aplikasi setiap kali menampilkan widget dalam ukuran yang berbeda.

Contoh kode berikut menunjukkan cara memberikan daftar tata letak.

Kotlin

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

  val viewMapping: Map<SizeF, RemoteViews> = mapOf(
    SizeF(100f, 100f) to smallView,
    SizeF(100f, 200f) to tallView,
    SizeF(200f, 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(100f, 100f), smallView);
  viewMapping.put(new SizeF(100f, 200f), tallView);
  viewMapping.put(new SizeF(200f, 100f), wideView);
  RemoteViews remoteViews = new RemoteViews(viewMapping);

  appWidgetManager.updateAppWidget(id, remoteViews);
}

Menyediakan tata letak yang tepat

Jika kumpulan kecil tata letak responsif tidak memungkinkan, Anda dapat memberikan tata letak yang berbeda dan telah disesuaikan dengan ukuran widget yang ditampilkan tersebut. Ini biasanya berupa dua ukuran untuk ponsel (mode potret dan lanskap) dan empat ukuran untuk perangkat foldable.

Untuk menerapkan solusi ini, aplikasi Anda harus melakukan langkah-langkah berikut:

  1. Kelebihan AppWidgetProvider#onAppWidgetOptionsChanged(...) yang dipanggil saat kumpulan ukuran berubah.

  2. Memanggil getAppWidgetManager#getAppWidgetOptions(...) yang menampilkan Bundle yang berisi ukuran.

  3. Mengakses kunci AppWidgetManager.OPTION_APPWIDGET_SIZES dari Bundle.

Contoh kode berikut menunjukkan cara menyediakan tata letak yang persis.

Kotlin

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

override fun onAppWidgetOptionsChanged(
  context: Context,
  manager: AppWidgetManager,
  id: Int,
  newOptions: Bundle?
) {
  super.onAppWidgetOptionsChanged(context, manager, 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 desired RemoteViews
  val remoteViews = RemoteViews(sizes.associateWith(::createRemoteViews))
  appWidgetManager.updateAppWidget(id, remoteViews)
}

Java

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

@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 desired RemoteViews.
    Map<SizesF, RemoteViews> viewMapping = new ArrayMap<>();
    for (SizeF size : sizes) {
      viewMapping.put(size, createRemoteViews(size));
    }
    RemoteViews remoteViews = new RemoteViews(viewMapping);
    appWidgetManager.updateAppWidget(id, remoteViews);
}

Kompatibilitas mundur dengan ukuran tata letak widget

Sebelumnya, Anda dapat memperoleh rentang ukuran widget menggunakan tambahan OPTION_APPWIDGET_MIN_WIDTH, OPTION_APPWIDGET_MIN_HEIGHT, OPTION_APPWIDGET_MAX_WIDTH, dan OPTION_APPWIDGET_MAX_HEIGHT dan memperkirakan ukuran widget, tetapi logika tersebut tidak berfungsi di semua situasi. Untuk widget yang menargetkan Android 12, sebaiknya beralih ke penyediaanresponsif atautata letak yang tepat seperti yang dijelaskan sebelumnya.

Meningkatkan pengalaman alat pilih widget aplikasi

Android 12 memungkinkan Anda meningkatkan pengalaman alat pilih widget untuk aplikasi dengan menambahkan pratinjau widget dinamis dan deskripsi widget.

Menambahkan pratinjau widget skalabel ke alat pilih widget

Di Android 12, pratinjau widget yang ditampilkan di alat pilih widget terdiri dari pratinjau skalabel yang akan Anda berikan sebagai tata letak XML yang disetel ke ukuran default widget. Sebelumnya, pratinjau widget adalah resource drawable statis yang dalam beberapa kasus menyebabkan pratinjau tidak menampilkan widget secara akurat setelah ditambahkan ke layar utama.

Untuk menerapkan pratinjau widget skalabel, gunakan atribut previewLayout dari elemen appwidget-provider untuk memberikan tata letak XML:

<appwidget-provider
  ...
  android:previewLayout="@layout/my_widget_preview">
</appwidget-provider>

Idealnya, tata letak ini harus sama dengan widget aktual dengan nilai default atau pengujian yang realistis.

Kompatibilitas mundur dengan pratinjau widget yang skalabel

Untuk mengaktifkan alat pilih widget di Android 11 atau yang lebih rendah guna menampilkan pratinjau widget Anda, lanjutkan menentukan atribut previewImage.

Jika Anda mengubah tampilan widget, pastikan juga untuk mengupdate gambar pratinjau.

Menambahkan deskripsi untuk widget Anda

Di Android 12, Anda dapat memberikan deskripsi untuk alat pilih widget yang akan ditampilkan untuk widget.

Teks alternatif

Berikan deskripsi untuk widget Anda menggunakan atribut deskripsi appwidget-provider:

<appwidget-provider
  ...
  android:description="@string/my_widget_description">
</appwidget-provider>

Kompatibilitas mundur dengan deskripsi widget

Aplikasi Anda dapat menggunakan atribut widgetDescription pada Android versi sebelumnya, tetapi tidak akan ditampilkan di alat pilih widget.

Mengaktifkan transisi yang lebih lancar

Di Android 12, peluncur memberikan transisi yang lebih lancar saat pengguna meluncurkan aplikasi Anda dari widget.

Untuk mengaktifkan transisi yang telah ditingkatkan ini, gunakan @android:id/background atau android.R.id.background untuk mengidentifikasi elemen latar belakang Anda:

// Top level layout of the widget.
<LinearLayout
  ...
  android:id="@android:id/background">
</LinearLayout>

Kompatibilitas mundur dengan transisi yang lebih lancar

Aplikasi Anda dapat menggunakan @android:id/background di versi Android sebelumnya, tetapi tidak akan berpengaruh.

Menggunakan koleksi RemoteViews sederhana

Android 12 menambahkan metode setRemoteAdapter(int viewId, RemoteViews.RemoteCollectionItems items), yang memungkinkan aplikasi meneruskan koleksi secara langsung saat mengisi ListView. Sebelumnya, saat menggunakan ListView, penting untuk menerapkan dan menyatakan RemoteViewsService agar menampilkan RemoteViewsFactory.

Jika koleksi tidak menggunakan set tata letak yang konstan (dengan kata lain, jika beberapa item terkadang hanya ada), gunakan setViewTypeCount untuk menentukan jumlah maksimum tata letak unik yang dapat dimuat koleksi.

Berikut adalah contoh cara mengimplementasikan koleksi RemoteViews sederhana.

Kotlin

remoteView.setRemoteAdapter(
  R.id.list_view,
  RemoteViews.RemoteCollectionItems.Builder()
    .addItem(/* id= */ ID_1, RemoteViews(...))
    .addItem(/* id= */ ID_2, RemoteViews(...))
    ...
    .setViewTypeCount(MAX_NUM_DIFFERENT_REMOTE_VIEWS_LAYOUTS)
    .build()
)

Java

remoteView.setRemoteAdapter(
  R.id.list_view,
  new RemoteViews.RemoteCollectionItems.Builder()
    .addItem(/* id= */ ID_1, new RemoteViews(...))
    .addItem(/* id= */ ID_2, new RemoteViews(...))
    ...
    .setViewTypeCount(MAX_NUM_DIFFERENT_REMOTE_VIEWS_LAYOUTS)
    .build()
);

Menggunakan modifikasi waktu proses RemoteView

Android 12 menambahkan beberapa metode RemoteViews yang memungkinkan modifikasi runtime atribut RemoteViews. Lihat referensi API RemoteViews untuk mengetahui daftar lengkap metode yang ditambahkan.

Contoh kode berikut menunjukkan cara menggunakan beberapa metode baru.

Kotlin

// Set the colors of a progress bar at runtime.
remoteView.setColorStateList(R.id.progress, "setProgressTintList", createProgressColorStateList())

// Specify exact sizes for margins.
remoteView.setViewLayoutMargin(R.id.text, RemoteViews.MARGIN_END, 8f, TypedValue.COMPLEX_UNIT_DP)

Java

// Set the colors of a progress bar at runtime.
remoteView.setColorStateList(R.id.progress, "setProgressTintList", createProgressColorStateList());

// Specify exact sizes for margins.
remoteView.setViewLayoutMargin(R.id.text, RemoteViews.MARGIN_END, 8f, TypedValue.COMPLEX_UNIT_DP);