В разделах ниже рассказывается, как создать базовый виджет приложения с помощью Glance.
Как объявить AppWidget в манифесте
После того как вы выполните настройку, объявите AppWidget и его метаданные в своем приложении.
Чтобы расширить приемник
AppWidgetсGlanceAppWidgetReceiver:class MyAppWidgetReceiver : GlanceAppWidgetReceiver() { override val glanceAppWidget: GlanceAppWidget = TODO("Create GlanceAppWidget") }
Зарегистрируйте поставщика виджета приложения в файле
AndroidManifest.xmlи связанном с ним файле метаданных:<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
Затем следуйте инструкциям в руководстве Как создать виджет, чтобы создать и определить информацию о виджете приложения в файле @xml/my_app_widget_info.
Единственное отличие для Glance заключается в том, что XML-файл initialLayout отсутствует, но его необходимо создать. Вы можете использовать стандартную разметку загрузки, предоставленную в библиотеке:
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:initialLayout="@layout/glance_default_loading_layout">
</appwidget-provider>
Как объявить XML-файл AppWidgetProviderInfo
Объект AppWidgetProviderInfo определяет основные характеристики виджета. Определите AppWidgetProviderInfo в XML-файле метаданных (res/xml/my_app_widget_info.xml) внутри элемента <appwidget-provider>:
<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>
Атрибуты размера виджета
На главном экране виджеты размещаются в окне на основе сетки ячеек определенной высоты и ширины. На большинстве главных экранов виджеты могут занимать только целое число ячеек сетки, например две ячейки по горизонтали и три по вертикали.
Атрибуты размера виджета позволяют задать размер по умолчанию, а также минимальный и максимальный размеры. В этом контексте размер виджета по умолчанию – это размер, который виджет занимает при первом добавлении на главный экран.
В таблице ниже описаны атрибуты <appwidget-provider>, относящиеся к размеру виджета.
| Атрибуты и описание | |
|---|---|
targetCellWidth и
targetCellHeight (Android 12),
minWidth и minHeight |
targetCellWidth и
targetCellHeight, а также minWidth и
minHeight. Это позволит приложению использовать minWidth и minHeight, если устройство пользователя
не поддерживает targetCellWidth и
targetCellHeight. Если поддерживается, атрибуты targetCellWidth и targetCellHeight имеют приоритет над атрибутами minWidth и minHeight.
|
minResizeWidth и minResizeHeight |
Укажите минимальный размер виджета. Эти значения определяют размер, при котором виджет становится нечитаемым или непригодным для использования. Эти атрибуты позволяют пользователю изменять размер виджета, уменьшая его по сравнению с размером по умолчанию. Атрибут minResizeWidth игнорируется, если его значение больше, чем значение атрибута minWidth, или если не включено горизонтальное изменение размера. Подробнее: resizeMode. Атрибут minResizeHeight игнорируется, если его значение больше, чем значение атрибута minHeight, или если вертикальное изменение размера не включено. |
maxResizeWidth и maxResizeHeight |
Укажите рекомендуемый максимальный размер виджета. Если значения не кратны размерам ячеек сетки, они округляются до ближайшего размера ячейки. Атрибут maxResizeWidth игнорируется, если он меньше minWidth или если не включено горизонтальное изменение размера. Подробнее: resizeMode. Аналогично, атрибут maxResizeHeight игнорируется, если его значение меньше, чем значение атрибута minHeight, или если вертикальное изменение размера не включено.
Появилась в Android 12. |
resizeMode |
Указывает правила, по которым можно изменять размер виджета. Этот атрибут позволяет изменять размер виджетов на главном экране по горизонтали, вертикали или в обоих направлениях. Пользователь нажимает на виджет и удерживает его, чтобы появились маркеры изменения размера, а затем перетаскивает горизонтальные или вертикальные маркеры, чтобы изменить размер виджета в сетке макета. Атрибут resizeMode может принимать следующие значения: horizontal, vertical и none. Чтобы объявить виджет изменяемым по горизонтали и вертикали, используйте horizontal|vertical. |
Пример
Чтобы показать, как атрибуты из таблицы выше влияют на размер виджета, предположим, что у нас есть следующие характеристики:
- Ширина ячейки сетки – 30 dp, высота – 50 dp.
- Ниже приведена спецификация атрибута:
<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 и более поздних версий:
Используйте атрибуты targetCellWidth и targetCellHeight в качестве размера виджета по умолчанию.
По умолчанию размер виджета – 2x2. Размер виджета можно изменить до 2 x 1 или 4 x 3.
Android 11 и более ранних версий
Атрибуты minWidth и minHeight используются для вычисления размера виджета по умолчанию.
Ширина по умолчанию = Math.ceil(80 / 30) = 3
Высота по умолчанию = Math.ceil(80 / 50) = 2
По умолчанию размер виджета – 3x2. Размер виджета можно уменьшить до 2 x 1 или увеличить до полноэкранного режима.
Дополнительные атрибуты виджетов
В таблице ниже описаны атрибуты <appwidget-provider>, относящиеся к другим характеристикам виджета, помимо его размера.
| Атрибуты и описание | |
|---|---|
updatePeriodMillis |
Определяет, как часто фреймворк виджета запрашивает обновление у GlanceAppWidgetReceiver, вызывая метод обратного вызова onUpdate(). Чтобы сэкономить заряд батареи, рекомендуем обновлять данные как можно реже, но не чаще раза в час.
Подробнее о том, когда обновлять виджеты… |
initialLayout |
Указывает на ресурс макета, который определяет макет загрузки виджета до того, как будут отрисованы композиции Glance UI. Вы можете использовать стандартную разметку загрузки, которая есть в библиотеке: @layout/glance_default_loading_layout. |
configure |
Определяет действие конфигурации, которое запускается, когда пользователь добавляет виджет. Подробнее о том, как разрешить пользователям настраивать виджеты приложений… |
description |
Описание виджета, которое будет показываться в окне выбора виджетов. Появилась в Android 12. |
previewLayout (Android 12) и previewImage (Android 11 и более ранние версии). |
|
autoAdvanceViewId |
Идентификатор представления подвиджета, который автоматически переключается хостом виджета. |
widgetCategory |
Указывает, можно ли показывать виджет на главном экране (home_screen), заблокированном экране (keyguard) или и там, и там. На устройствах с Android 5.0 и более поздних версий можно использовать только home_screen. |
widgetFeatures |
Объявляет функции, поддерживаемые виджетом. Например, если конфигурация виджета необязательна, укажите и configuration_optional, и reconfigurable. |
Определение: GlanceAppWidget
Создайте новый класс, который наследует
GlanceAppWidgetи переопределяет методprovideGlance. Этот метод позволяет загружать данные, необходимые для отрисовки виджета: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") } } }
Создайте его экземпляр в
glanceAppWidgetнаGlanceAppWidgetReceiver:class MyAppWidgetReceiver : GlanceAppWidgetReceiver() { // Let MyAppWidgetReceiver know which GlanceAppWidget to use override val glanceAppWidget: GlanceAppWidget = MyAppWidget() }
Вы настроили AppWidget с помощью Glance.
Используйте класс GlanceAppWidgetReceiver для обработки широковещательных рассылок виджетов
Виджет координат GlanceAppWidgetReceiver передает данные о состоянии платформы, расширяя возможности AppWidgetProvider. Он получает события платформы, когда виджет обновляется, удаляется, включается или отключается, и преобразует их в запросы жизненного цикла Compose.
Как добавить виджет в манифест
Объявите подкласс класса GlanceAppWidgetReceiver как широковещательный приемник в файле AndroidManifest.xml:
<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> требуется атрибут android:name, который указывает на класс получателя. Получатель должен принять ACTION_APPWIDGET_UPDATE
действие трансляции в <intent-filter>.
Элемент <meta-data> должен содержать имя android.appwidget.provider, а атрибут android:resource должен указывать на XML-ресурс метаданных AppWidgetProviderInfo (@xml/my_app_widget_info).
Как реализовать класс GlanceAppWidgetReceiver
В Glance вы расширяете GlanceAppWidgetReceiver, а не AppWidgetProvider напрямую. Чтобы реализовать эту функцию, свяжите приемник с экземпляром GlanceAppWidget. Основные обратные вызовы, доступные в GlanceAppWidgetReceiver, работают следующим образом:
onUpdate(): автоматически переопределяется Glance для выполнения обновлений композиции. Если вы вручную переопределяетеonUpdate, то должны вызватьsuper.onUpdate, чтобы Glance мог успешно запускать потоки композиции.onAppWidgetOptionsChanged(): вызывается, когда виджет размещается или изменяется его размер. Варианты Glance считывают данные из пакетов, поэтому макет автоматически подстраивается под размеры во время выполнения.onDeleted(Context, IntArray): вызывается, когда пользователь удаляет определенный экземпляр виджета.onEnabled(Context): срабатывает при успешном создании первого экземпляра виджета. Отлично подходит для переноса данных в глобальном масштабе.onDisabled(Context)– вызывается при удалении последнего активного экземпляра поставщика.onReceive(Context, Intent): перехватывает каждую трансляцию платформы перед определенными методами обратного вызова. В пользовательской логике приемника необходимо вызыватьsuper.onReceive(context, intent). Не вызывайтеgoAsyncсамостоятельно, поскольку Glance автоматически асинхронно направляет рабочие процессы.
Получение широковещательных намерений виджета
GlanceAppWidgetReceiver фильтрует и обрабатывает следующие основные широковещательные намерения виджетов платформы:
ACTION_APPWIDGET_UPDATEACTION_APPWIDGET_DELETEDACTION_APPWIDGET_ENABLEDACTION_APPWIDGET_DISABLEDACTION_APPWIDGET_OPTIONS_CHANGED
Создание интерфейса
Ниже приведен фрагмент кода, в котором показано, как создать интерфейс:
/* 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>() ) } } } }
Приведенный выше фрагмент кода выполняет следующие действия:
- В элементе верхнего уровня
Columnобъекты размещаются вертикально друг за другом. - Размер элемента
Columnувеличивается, чтобы заполнить доступное пространство (с помощьюGlanceModifier), а его контент выравнивается по верхнему краю (verticalAlignment) и центрируется по горизонтали (horizontalAlignment). - Контент элемента
Columnопределяется с помощью лямбда-функции. Порядок имеет значение.- Первый элемент в
Column– это компонентTextс12.dpотступа. - Второй элемент – это
Row, в котором объекты размещаются горизонтально друг за другом, а два элементаButtonsвыравниваются по горизонтали по центру (horizontalAlignment). Окончательный вид зависит от доступного пространства. На изображении ниже показано, как это может выглядеть.
- Первый элемент в
Вы можете изменить значения выравнивания или применить другие значения модификаторов (например, отступов), чтобы изменить положение и размер компонентов. Полный список компонентов, параметров и доступных модификаторов для каждого класса приведен в справочной документации.
Как реализовать скругленные углы
В Android 12 появились системные параметры, позволяющие динамически настраивать радиус скругления углов виджетов приложений:
system_app_widget_background_radius– радиус скругления углов контейнера фона виджета (не более 28 д. п.).- Внутренний радиус. Чтобы контент не обрезался, рассчитайте пропорциональный радиус для внутреннего контента на основе контура системного фона:
systemRadiusValue - widgetPadding
В Glance можно динамически применять свойства размера радиуса скругления углов в композиции с помощью GlanceModifier.cornerRadius(android.R.dimen.system_app_widget_background_radius).
Для обеспечения обратной совместимости на устройствах с Android 11 (уровень API 30) или более ранних версий реализуйте собственные атрибуты и резервные ресурсы для собственных тем:
/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>