Виджеты приложений — это миниатюрные представления приложений, которые можно встраивать в другие приложения, например на главный экран, и получать периодические обновления. Эти представления называются виджетами в пользовательском интерфейсе, и вы можете опубликовать их с помощью поставщика виджетов приложения (или поставщика виджетов ). Компонент приложения, содержащий другие виджеты, называется хостом виджета приложения (или хостом виджета ). На рис. 1 показан пример музыкального виджета:
В этом документе описывается, как опубликовать виджет с помощью поставщика виджетов. Подробные сведения о создании собственного AppWidgetHost
для размещения виджетов приложений см. в разделе Создание хоста виджетов .
Информацию о том, как создать виджет, см. в разделе Обзор виджетов приложения .
Компоненты виджета
Для создания виджета вам потребуются следующие основные компоненты:
- Объект
AppWidgetProviderInfo
- Описывает метаданные виджета, такие как макет виджета, частота обновления и класс
AppWidgetProvider
.AppWidgetProviderInfo
определяется в XML , как описано в этом документе. - Класс
AppWidgetProvider
- Определяет основные методы, которые позволяют программно взаимодействовать с виджетом. Через него вы получаете трансляции, когда виджет обновляется, включается, отключается или удаляется. Вы объявляете
AppWidgetProvider
в манифесте , а затем реализуете его, как описано в этом документе. - Посмотреть макет
- Определяет исходный макет виджета. Макет определяется в XML , как описано в этом документе.
На рис. 2 показано, как эти компоненты вписываются в общий процесс обработки виджетов приложения.
Если ваш виджет требует пользовательской настройки, реализуйте действие по настройке виджета приложения. Это действие позволяет пользователям изменять настройки виджета, например часовой пояс для виджета часов.
- Начиная с Android 12 (уровень API 31), вы можете предоставить конфигурацию по умолчанию и позволить пользователям перенастроить виджет позже. Дополнительные сведения см. в разделах «Использовать конфигурацию виджета по умолчанию» и «Разрешить пользователям перенастраивать размещенные виджеты» .
- В Android 11 (уровень API 30) или ниже это действие запускается каждый раз, когда пользователь добавляет виджет на свой главный экран.
Мы также рекомендуем следующие улучшения: гибкие макеты виджетов , различные улучшения , расширенные виджеты , виджеты-коллекции и создание хоста виджетов .
Объявите XML AppWidgetProviderInfo.
Объект AppWidgetProviderInfo
определяет основные качества виджета. Определите объект AppWidgetProviderInfo
в файле ресурсов XML, используя один элемент <appwidget-provider>
, и сохраните его в папке res/xml/
проекта.
Это показано в следующем примере:
<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/example_loading_appwidget"
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. Размер виджета можно изменить до 2x1 или до 4x3.
Android 11 и более ранние версии:
Используйте атрибуты minWidth
и minHeight
для вычисления размера виджета по умолчанию.
Ширина по умолчанию = Math.ceil(80 / 30)
= 3.
Высота по умолчанию = Math.ceil(80 / 50)
= 2.
По умолчанию размер виджета составляет 3x2. Размер виджета можно изменить до 2х1 или до полноэкранного.
Дополнительные атрибуты виджета
В следующей таблице описаны атрибуты <appwidget-provider>
, относящиеся к качествам, отличным от размера виджета.
Атрибуты и описание | |
---|---|
updatePeriodMillis | Определяет, как часто платформа виджетов запрашивает обновление у AppWidgetProvider , вызывая метод обратного вызова onUpdate() . При этом значении фактическое обновление не гарантируется точно в срок, и мы рекомендуем обновлять как можно реже — не чаще одного раза в час — для экономии заряда батареи. Полный список рекомендаций по выбору подходящего периода обновления см. в разделе «Оптимизация обновления содержимого виджета» . |
initialLayout | Указывает на ресурс макета, определяющий макет виджета. |
configure | Определяет действие, которое запускается, когда пользователь добавляет виджет, позволяя ему настраивать свойства виджета. См. раздел Разрешение пользователям настраивать виджеты . Начиная с Android 12, ваше приложение может пропускать начальную настройку. Подробности см. в разделе Использование конфигурации виджета по умолчанию . |
description | Указывает описание средства выбора виджета, которое будет отображаться для вашего виджета. Представлено в Android 12. |
previewLayout (Android 12) и previewImage (Android 11 и более ранние версии) |
previewImage previewLayout , чтобы ваше приложение могло вернуться к previewImage если устройство пользователя не previewLayout . Дополнительные сведения см. в разделе Обратная совместимость с масштабируемыми предпросмотрами виджетов . |
autoAdvanceViewId | Указывает идентификатор представления подпредставления виджета, которое автоматически расширяется хостом виджета. |
widgetCategory | Объявляет, может ли ваш виджет отображаться на главном экране ( home_screen ), экране блокировки ( keyguard ) или на обоих. Для Android 5.0 и выше допустим только home_screen . |
widgetFeatures | Объявляет функции, поддерживаемые виджетом. Например, если вы хотите, чтобы ваш виджет использовал конфигурацию по умолчанию, когда пользователь добавляет его, укажите флаги configuration_optional и reconfigurable . Это обходит запуск действия по настройке после того, как пользователь добавляет виджет. Пользователь по-прежнему может впоследствии перенастроить виджет . |
Используйте класс AppWidgetProvider для обработки трансляций виджетов.
Класс AppWidgetProvider
обрабатывает широковещательные рассылки виджетов и обновляет виджет в ответ на события жизненного цикла виджета. В следующих разделах описано, как объявить AppWidgetProvider
в манифесте и затем реализовать его.
Объявить виджет в манифесте
Сначала объявите класс AppWidgetProvider
в файле AndroidManifest.xml
вашего приложения, как показано в следующем примере:
<receiver android:name="ExampleAppWidgetProvider"
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/example_appwidget_info" />
</receiver>
Элементу <receiver>
требуется атрибут android:name
, который указывает AppWidgetProvider
, используемый виджетом. Компонент нельзя экспортировать, если отдельный процесс не требует трансляции в ваш AppWidgetProvider
, что обычно не происходит.
Элемент <intent-filter>
должен включать элемент <action>
с атрибутом android:name
. Этот атрибут указывает, что AppWidgetProvider
принимает широковещательную рассылку ACTION_APPWIDGET_UPDATE
. Это единственная трансляция, которую вы должны явно заявить. AppWidgetManager
автоматически отправляет все остальные широковещательные сообщения виджетов в AppWidgetProvider
по мере необходимости.
Элемент <meta-data>
определяет ресурс AppWidgetProviderInfo
и требует следующих атрибутов:
-
android:name
: указывает имя метаданных. Используйтеandroid.appwidget.provider
, чтобы идентифицировать данные как дескрипторAppWidgetProviderInfo
. -
android:resource
: указывает расположение ресурсаAppWidgetProviderInfo
.
Реализуйте класс AppWidgetProvider.
Класс AppWidgetProvider
расширяет BroadcastReceiver
как удобный класс для обработки широковещательных сообщений виджетов. Он получает только широковещательные сообщения о событиях, которые имеют отношение к виджету, например, когда виджет обновляется, удаляется, включается и отключается. Когда происходят эти широковещательные события, вызываются следующие методы AppWidgetProvider
:
-
onUpdate()
- Это вызывается для обновления виджета с интервалами, определяемыми атрибутом
updatePeriodMillis
вAppWidgetProviderInfo
. Дополнительную информацию смотрите в таблице, описывающей дополнительные атрибуты виджета на этой странице. - Этот метод также вызывается, когда пользователь добавляет виджет, поэтому он выполняет необходимые настройки, такие как определение обработчиков событий для объектов
View
или запуск заданий по загрузке данных для отображения в виджете. Однако если вы объявляете действие настройки без флагаconfiguration_optional
, этот метод не вызывается, когда пользователь добавляет виджет, но он вызывается для последующих обновлений. Ответственность за выполнение первого обновления после завершения настройки лежит на деятельности по настройке. Дополнительную информацию см. в разделе Разрешить пользователям настраивать виджеты приложений . - Самый важный обратный вызов —
onUpdate()
. Дополнительную информацию см. в разделе «Обработка событий с помощью классаonUpdate()
на этой странице. -
onAppWidgetOptionsChanged()
Это вызывается при первом размещении виджета и при каждом изменении размера виджета. Используйте этот обратный вызов, чтобы показать или скрыть контент в зависимости от диапазонов размеров виджета. Получите диапазоны размеров (а, начиная с Android 12, список возможных размеров, которые может принимать экземпляр виджета), вызвав
getAppWidgetOptions()
, который возвращаетBundle
, который включает в себя следующее:-
OPTION_APPWIDGET_MIN_WIDTH
: содержит нижнюю границу ширины экземпляра виджета в единицах dp. -
OPTION_APPWIDGET_MIN_HEIGHT
: содержит нижнюю границу высоты экземпляра виджета в единицах dp. -
OPTION_APPWIDGET_MAX_WIDTH
: содержит верхнюю границу ширины экземпляра виджета в единицах dp. -
OPTION_APPWIDGET_MAX_HEIGHT
: содержит верхнюю границу высоты экземпляра виджета в единицах dp. -
OPTION_APPWIDGET_SIZES
: содержит список возможных размеров (List<SizeF>
) в единицах dp, которые может принимать экземпляр виджета. Представлено в Android 12.
-
-
onDeleted(Context, int[])
Это вызывается каждый раз, когда виджет удаляется с хоста виджетов.
-
onEnabled(Context)
Это вызывается, когда экземпляр виджета создается впервые. Например, если пользователь добавляет два экземпляра вашего виджета, он вызывается только в первый раз. Если вам нужно открыть новую базу данных или выполнить другую настройку, которую нужно выполнить только один раз для всех экземпляров виджета, то это хорошее место для этого.
-
onDisabled(Context)
Это вызывается, когда последний экземпляр вашего виджета удаляется с хоста виджетов. Здесь вы очищаете любую работу, выполненную в
onEnabled(Context)
, например удаление временной базы данных.-
onReceive(Context, Intent)
Это вызывается для каждой трансляции и перед каждым из предыдущих методов обратного вызова. Обычно вам не нужно реализовывать этот метод, поскольку реализация
AppWidgetProvider
по умолчанию фильтрует все широковещательные сообщения виджетов и вызывает соответствующие предыдущие методы.
Вы должны объявить реализацию класса AppWidgetProvider
как получатель широковещательной рассылки, используя элемент <receiver>
в AndroidManifest
. Дополнительные сведения см. в разделе «Объявление виджета в манифесте» на этой странице.
Обработка событий с помощью класса onUpdate().
Самый важный обратный вызов AppWidgetProvider
— это onUpdate()
, поскольку он вызывается при добавлении каждого виджета на хост, если только вы не используете действие настройки без флага configuration_optional
. Если ваш виджет принимает какие-либо события взаимодействия с пользователем, зарегистрируйте обработчики событий в этом обратном вызове. Если ваш виджет не создает временные файлы или базы данных и не выполняет другую работу, требующую очистки, то onUpdate()
может быть единственным методом обратного вызова, который вам нужно определить.
Например, если вам нужен виджет с кнопкой, которая запускает действие при нажатии, вы можете использовать следующую реализацию AppWidgetProvider
:
Котлин
class ExampleAppWidgetProvider : AppWidgetProvider() { override fun onUpdate( context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray ) { // Perform this loop procedure for each widget that belongs to this // provider. appWidgetIds.forEach { appWidgetId -> // Create an Intent to launch ExampleActivity. val pendingIntent: PendingIntent = PendingIntent.getActivity( /* context = */ context, /* requestCode = */ 0, /* intent = */ Intent(context, ExampleActivity::class.java), /* flags = */ PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE ) // Get the layout for the widget and attach an onClick listener to // the button. val views: RemoteViews = RemoteViews( context.packageName, R.layout.appwidget_provider_layout ).apply { setOnClickPendingIntent(R.id.button, pendingIntent) } // Tell the AppWidgetManager to perform an update on the current // widget. appWidgetManager.updateAppWidget(appWidgetId, views) } } }
Ява
public class ExampleAppWidgetProvider extends AppWidgetProvider { public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { // Perform this loop procedure for each widget that belongs to this // provider. for (int i=0; i < appWidgetIds.length; i++) { int appWidgetId = appWidgetIds[i]; // Create an Intent to launch ExampleActivity Intent intent = new Intent(context, ExampleActivity.class); PendingIntent pendingIntent = PendingIntent.getActivity( /* context = */ context, /* requestCode = */ 0, /* intent = */ intent, /* flags = */ PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE ); // Get the layout for the widget and attach an onClick listener to // the button. RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.example_appwidget_layout); views.setOnClickPendingIntent(R.id.button, pendingIntent); // Tell the AppWidgetManager to perform an update on the current app // widget. appWidgetManager.updateAppWidget(appWidgetId, views); } } }
Этот AppWidgetProvider
определяет только метод onUpdate()
, используя его для создания PendingIntent
, который запускает Activity
и прикрепляет его к кнопке виджета с помощью setOnClickPendingIntent(int, PendingIntent)
. Он включает в себя цикл, который перебирает каждую запись в appWidgetIds
, который представляет собой массив идентификаторов, идентифицирующих каждый виджет, созданный этим поставщиком. Если пользователь создает более одного экземпляра виджета, все они обновляются одновременно. Однако для всех экземпляров виджета управляется только одно расписание updatePeriodMillis
. Например, если расписание обновления определено каждые два часа, а второй экземпляр виджета добавляется через час после первого, то они оба обновляются в период, определенный первым и вторым периодом обновления. игнорируется. Они оба обновляются каждые два часа, а не каждый час.
Дополнительные сведения см. в примере класса ExampleAppWidgetProvider.java
.
Получение намерений трансляции виджета
AppWidgetProvider
— это удобный класс. Если вы хотите получать трансляции виджета напрямую, вы можете реализовать свой собственный BroadcastReceiver
или переопределить обратный вызов onReceive(Context,Intent)
. Намерения, о которых вам нужно заботиться, следующие:
-
ACTION_APPWIDGET_UPDATE
-
ACTION_APPWIDGET_DELETED
-
ACTION_APPWIDGET_ENABLED
-
ACTION_APPWIDGET_DISABLED
-
ACTION_APPWIDGET_OPTIONS_CHANGED
Создайте макет виджета
Вы должны определить первоначальный макет вашего виджета в XML и сохранить его в каталоге res/layout/
проекта. Подробности см. в Руководстве по проектированию .
Создать макет виджета несложно, если вы знакомы с макетами . Однако имейте в виду, что макеты виджетов основаны на RemoteViews
, который поддерживает не все виды виджетов макетов и представлений. Вы не можете использовать собственные представления или подклассы представлений, поддерживаемых RemoteViews
.
RemoteViews
также поддерживает ViewStub
— невидимое View
нулевого размера, которое можно использовать для ленивого раздувания ресурсов макета во время выполнения.
Поддержка поведения с сохранением состояния
В Android 12 добавлена поддержка поведения с отслеживанием состояния с использованием следующих существующих компонентов:
Виджет по-прежнему не имеет состояния. Ваше приложение должно хранить состояние и регистрироваться для событий изменения состояния.
В следующем примере кода показано, как реализовать эти компоненты.
Котлин
// 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 has 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) )
Ява
// 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 has 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));
Предоставьте два макета: один предназначен для устройств под управлением Android 12 или более поздней версии в res/layout-v31
, а другой — для предыдущей версии Android 11 или более ранней версии в папке res/layout
по умолчанию.
Реализуйте закругленные углы
В Android 12 представлены следующие системные параметры для установки радиусов закругленных углов вашего виджета:
system_app_widget_background_radius
: угловой радиус фона виджета, который никогда не превышает 28 dp.system_app_widget_inner_radius
: угловой радиус любого вида внутри виджета. Это ровно на 8 dp меньше радиуса фона, чтобы обеспечить хорошее выравнивание при использовании заполнения 8 dp.
В следующем примере показан виджет, который использует system_app_widget_background_radius
для угла виджета и system_app_widget_inner_radius
для просмотра внутри виджета.
1 Угол виджета.
2 Угол обзора внутри виджета.
Важные соображения относительно закругленных углов
- Сторонние программы запуска и производители устройств могут переопределить параметр
system_app_widget_background_radius
, чтобы он был меньше 28 dp. Параметрsystem_app_widget_inner_radius
всегда на 8 dp меньше значенияsystem_app_widget_background_radius
. - Если ваш виджет не использует
@android:id/background
и не определяет фон, который обрезает его содержимое на основе контура (если дляandroid:clipToOutline
установлено значениеtrue
, средство запуска автоматически идентифицирует фон и обрезает виджет, используя прямоугольник с закругленными углами. до 16 дп. См. раздел Убедитесь, что ваш виджет совместим с Android 12 .
Для совместимости виджета с предыдущими версиями Android мы рекомендуем определить пользовательские атрибуты и использовать пользовательскую тему для их переопределения для Android 12, как показано в следующих примерах XML-файлов:
/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" />
Виджеты приложений — это миниатюрные представления приложений, которые можно встраивать в другие приложения, например на главный экран, и получать периодические обновления. Эти представления называются виджетами в пользовательском интерфейсе, и вы можете опубликовать их с помощью поставщика виджетов приложения (или поставщика виджетов ). Компонент приложения, содержащий другие виджеты, называется хостом виджета приложения (или хостом виджета ). На рис. 1 показан пример музыкального виджета:
В этом документе описывается, как опубликовать виджет с помощью поставщика виджетов. Подробные сведения о создании собственного AppWidgetHost
для размещения виджетов приложений см. в разделе Создание хоста виджетов .
Информацию о том, как создать виджет, см. в разделе Обзор виджетов приложения .
Компоненты виджета
Для создания виджета вам потребуются следующие основные компоненты:
- Объект
AppWidgetProviderInfo
- Описывает метаданные виджета, такие как макет виджета, частота обновления и класс
AppWidgetProvider
.AppWidgetProviderInfo
определяется в XML , как описано в этом документе. - Класс
AppWidgetProvider
- Определяет основные методы, которые позволяют программно взаимодействовать с виджетом. Через него вы получаете трансляции, когда виджет обновляется, включается, отключается или удаляется. Вы объявляете
AppWidgetProvider
в манифесте , а затем реализуете его, как описано в этом документе. - Посмотреть макет
- Определяет исходный макет виджета. Макет определяется в XML , как описано в этом документе.
На рис. 2 показано, как эти компоненты вписываются в общий процесс обработки виджетов приложения.
Если ваш виджет требует пользовательской настройки, реализуйте действие по настройке виджета приложения. Это действие позволяет пользователям изменять настройки виджета, например часовой пояс для виджета часов.
- Начиная с Android 12 (уровень API 31), вы можете предоставить конфигурацию по умолчанию и позволить пользователям перенастроить виджет позже. Дополнительные сведения см. в разделах «Использовать конфигурацию виджета по умолчанию» и «Разрешить пользователям перенастраивать размещенные виджеты» .
- В Android 11 (уровень API 30) или ниже это действие запускается каждый раз, когда пользователь добавляет виджет на свой главный экран.
Мы также рекомендуем следующие улучшения: гибкие макеты виджетов , различные улучшения , расширенные виджеты , виджеты-коллекции и создание хоста виджетов .
Объявите XML AppWidgetProviderInfo.
Объект AppWidgetProviderInfo
определяет основные качества виджета. Определите объект AppWidgetProviderInfo
в файле ресурсов XML, используя один элемент <appwidget-provider>
, и сохраните его в папке res/xml/
проекта.
Это показано в следующем примере:
<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/example_loading_appwidget"
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. Размер виджета можно изменить до 2x1 или до 4x3.
Android 11 и более ранние версии:
Используйте атрибуты minWidth
и minHeight
для вычисления размера виджета по умолчанию.
Ширина по умолчанию = Math.ceil(80 / 30)
= 3.
Высота по умолчанию = Math.ceil(80 / 50)
= 2.
По умолчанию размер виджета составляет 3x2. Размер виджета можно изменить до 2х1 или до полноэкранного.
Дополнительные атрибуты виджета
В следующей таблице описаны атрибуты <appwidget-provider>
, относящиеся к качествам, отличным от размера виджета.
Атрибуты и описание | |
---|---|
updatePeriodMillis | Определяет, как часто платформа виджетов запрашивает обновление у AppWidgetProvider , вызывая метод обратного вызова onUpdate() . При этом значении фактическое обновление не гарантируется точно в срок, и мы рекомендуем обновлять как можно реже — не чаще одного раза в час — для экономии заряда батареи. Полный список рекомендаций по выбору подходящего периода обновления см. в разделе «Оптимизация обновления содержимого виджета» . |
initialLayout | Указывает на ресурс макета, определяющий макет виджета. |
configure | Определяет действие, которое запускается, когда пользователь добавляет виджет, позволяя ему настраивать свойства виджета. См. раздел Разрешение пользователям настраивать виджеты . Начиная с Android 12, ваше приложение может пропускать начальную настройку. Подробности см. в разделе Использование конфигурации виджета по умолчанию . |
description | Указывает описание средства выбора виджета, которое будет отображаться для вашего виджета. Представлено в Android 12. |
previewLayout (Android 12) и previewImage (Android 11 и более ранние версии) |
previewImage previewLayout , чтобы ваше приложение могло вернуться к previewImage если устройство пользователя не previewLayout . Дополнительные сведения см. в разделе Обратная совместимость с масштабируемыми предпросмотрами виджетов . |
autoAdvanceViewId | Указывает идентификатор представления подпредставления виджета, которое автоматически расширяется хостом виджета. |
widgetCategory | Объявляет, может ли ваш виджет отображаться на главном экране ( home_screen ), экране блокировки ( keyguard ) или на обоих. Для Android 5.0 и выше допустим только home_screen . |
widgetFeatures | Объявляет функции, поддерживаемые виджетом. Например, если вы хотите, чтобы ваш виджет использовал конфигурацию по умолчанию, когда пользователь добавляет его, укажите флаги configuration_optional и reconfigurable . Это обходит запуск действия по настройке после того, как пользователь добавляет виджет. Пользователь по-прежнему может впоследствии перенастроить виджет . |
Используйте класс AppWidgetProvider для обработки трансляций виджетов.
Класс AppWidgetProvider
обрабатывает широковещательную рассылку виджетов и обновляет виджет в ответ на события жизненного цикла виджета. В следующих разделах описано, как объявить AppWidgetProvider
в манифесте и затем реализовать его.
Объявить виджет в манифесте
Сначала объявите класс AppWidgetProvider
в файле AndroidManifest.xml
вашего приложения, как показано в следующем примере:
<receiver android:name="ExampleAppWidgetProvider"
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/example_appwidget_info" />
</receiver>
Элементу <receiver>
требуется атрибут android:name
, который указывает AppWidgetProvider
, используемый виджетом. Компонент нельзя экспортировать, если отдельный процесс не требует трансляции в ваш AppWidgetProvider
, что обычно не происходит.
Элемент <intent-filter>
должен включать элемент <action>
с атрибутом android:name
. Этот атрибут указывает, что AppWidgetProvider
принимает широковещательную рассылку ACTION_APPWIDGET_UPDATE
. Это единственная трансляция, которую вы должны явно заявить. AppWidgetManager
автоматически отправляет все остальные широковещательные сообщения виджетов в AppWidgetProvider
по мере необходимости.
Элемент <meta-data>
указывает ресурс AppWidgetProviderInfo
и требует следующих атрибутов:
-
android:name
: указывает имя метаданных. Используйтеandroid.appwidget.provider
, чтобы идентифицировать данные как дескрипторAppWidgetProviderInfo
. -
android:resource
: указывает расположение ресурсаAppWidgetProviderInfo
.
Реализуйте класс AppWidgetProvider.
Класс AppWidgetProvider
расширяет BroadcastReceiver
как удобный класс для обработки широковещательных сообщений виджетов. Он получает только широковещательные сообщения о событиях, которые имеют отношение к виджету, например, когда виджет обновляется, удаляется, включается и отключается. Когда происходят эти широковещательные события, вызываются следующие методы AppWidgetProvider
:
-
onUpdate()
- Это вызывается для обновления виджета с интервалами, определяемыми атрибутом
updatePeriodMillis
вAppWidgetProviderInfo
. Дополнительную информацию см. в таблице, описывающей дополнительные атрибуты виджета на этой странице. - Этот метод также вызывается, когда пользователь добавляет виджет, поэтому он выполняет необходимые настройки, такие как определение обработчиков событий для объектов
View
или запуск заданий по загрузке данных для отображения в виджете. Однако, если вы объявляете деятельность по конфигурации без флагаconfiguration_optional
, этот метод не вызывается, когда пользователь добавляет виджет, но он требуется для последующих обновлений. Занимание конфигурации несет ответственность за выполнение первого обновления при завершении конфигурации. См. Enable пользователи настраивают виджеты приложений для получения дополнительной информации. - Самый важный обратный вызов -
onUpdate()
. См. Ручке событий с классомonUpdate()
на этой странице для получения дополнительной информации. -
onAppWidgetOptionsChanged()
Это вызывается, когда виджет сначала размещен, и в любое время, когда виджет будет изменен. Используйте этот обратный вызов, чтобы показать или скрыть контент на основе диапазонов размера виджета. Получите диапазоны размеров - и, начиная с Android 12, список возможных размеров, который может принять экземпляр виджета, - вызовет
getAppWidgetOptions()
, который возвращаетBundle
, который включает в себя следующее:-
OPTION_APPWIDGET_MIN_WIDTH
: содержит нижнюю границу на ширине, в единицах DP, экземпляра виджета. -
OPTION_APPWIDGET_MIN_HEIGHT
: содержит нижнюю границу на высоте, в единицах DP, экземпляра виджета. -
OPTION_APPWIDGET_MAX_WIDTH
: содержит верхнюю границу на ширине, в единицах DP, экземпляра виджета. -
OPTION_APPWIDGET_MAX_HEIGHT
: содержит верхнюю границу на высоте, в единицах DP, экземпляра виджета. -
OPTION_APPWIDGET_SIZES
: содержит список возможных размеров (List<SizeF>
), в единицах DP, который может принять экземпляр виджета. Представлено в Android 12.
-
-
onDeleted(Context, int[])
Это называется каждый раз, когда виджет удаляется с хоста виджетов.
-
onEnabled(Context)
Это вызывается, когда экземпляр виджета создается в первый раз. Например, если пользователь добавляет два экземпляра вашего виджета, его называют только в первый раз. Если вам нужно открыть новую базу данных или выполнить другую настройку, которая должна произойти только один раз для всех экземпляров виджетов, то это хорошее место для этого.
-
onDisabled(Context)
Это вызывается, когда последний экземпляр вашего виджета удаляется с хоста виджетов. Здесь вы очищаете любую работу, выполненную в
onEnabled(Context)
, например, удаление временной базы данных.-
onReceive(Context, Intent)
Это требуется для каждой трансляции и до каждого из предыдущих методов обратного вызова. Обычно вам не нужно реализовать этот метод, потому что реализация
AppWidgetProvider
фильтровала все трансляции виджетов и вызывает предыдущие методы.
Вы должны объявить свою реализацию класса AppWidgetProvider
в качестве получателя вещания, используя элемент <receiver>
в AndroidManifest
. См . Объявите виджет на манифесте на этой странице для получения дополнительной информации.
Обрабатывать события с классом onupdate ()
Наиболее важным обратным вызовом AppWidgetProvider
является onUpdate()
, поскольку он вызывается, когда каждый виджет добавляется на хост, если вы не используете активность конфигурации без флага configuration_optional
. Если ваш виджет принимает какие -либо события взаимодействия с пользователем, зарегистрируйте обработчики событий в этом обратном вызове. Если ваш виджет не создает временные файлы или базы данных, и не выполняет другие работы, которые требуют очистки, то onUpdate()
может быть единственным методом обратного вызова, который вам необходимо определить.
Например, если вам нужен виджет с кнопкой, которая запускает деятельность при нажатии, вы можете использовать следующую реализацию AppWidgetProvider
:
Котлин
class ExampleAppWidgetProvider : AppWidgetProvider() { override fun onUpdate( context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray ) { // Perform this loop procedure for each widget that belongs to this // provider. appWidgetIds.forEach { appWidgetId -> // Create an Intent to launch ExampleActivity. val pendingIntent: PendingIntent = PendingIntent.getActivity( /* context = */ context, /* requestCode = */ 0, /* intent = */ Intent(context, ExampleActivity::class.java), /* flags = */ PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE ) // Get the layout for the widget and attach an onClick listener to // the button. val views: RemoteViews = RemoteViews( context.packageName, R.layout.appwidget_provider_layout ).apply { setOnClickPendingIntent(R.id.button, pendingIntent) } // Tell the AppWidgetManager to perform an update on the current // widget. appWidgetManager.updateAppWidget(appWidgetId, views) } } }
Ява
public class ExampleAppWidgetProvider extends AppWidgetProvider { public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { // Perform this loop procedure for each widget that belongs to this // provider. for (int i=0; i < appWidgetIds.length; i++) { int appWidgetId = appWidgetIds[i]; // Create an Intent to launch ExampleActivity Intent intent = new Intent(context, ExampleActivity.class); PendingIntent pendingIntent = PendingIntent.getActivity( /* context = */ context, /* requestCode = */ 0, /* intent = */ intent, /* flags = */ PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE ); // Get the layout for the widget and attach an onClick listener to // the button. RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.example_appwidget_layout); views.setOnClickPendingIntent(R.id.button, pendingIntent); // Tell the AppWidgetManager to perform an update on the current app // widget. appWidgetManager.updateAppWidget(appWidgetId, views); } } }
Этот AppWidgetProvider
определяет только метод onUpdate()
, используя его для создания PendingIntent
, который запускает Activity
и прикрепляет его к кнопке виджета с использованием setOnClickPendingIntent(int, PendingIntent)
. Он включает в себя цикл, который итерация проходит через каждую запись в appWidgetIds
, который представляет собой массив идентификаторов, которые идентифицируют каждый виджет, созданный этим поставщиком. Если пользователь создает более одного экземпляра виджета, то все они обновляются одновременно. Тем не менее, только одно расписание updatePeriodMillis
управляется для всех экземпляров виджета. Например, если график обновления определяется как каждые два часа, а второй экземпляр виджета добавляется через час после первого, тогда они оба обновляются в период, определяемый первым, и второй период обновления игнорируется. Они оба обновляют каждые два часа, не каждый час.
См. Примерный класс примеров ExampleAppWidgetProvider.java
для получения более подробной информации.
Получить намерения трансляции виджетов
AppWidgetProvider
- это удобный класс. Если вы хотите получить трансляцию виджета напрямую, вы можете реализовать свой собственный BroadcastReceiver
или переопределить обратный вызов onReceive(Context,Intent)
. Намерения, о которых вам нужно заботиться, являются следующими:
-
ACTION_APPWIDGET_UPDATE
-
ACTION_APPWIDGET_DELETED
-
ACTION_APPWIDGET_ENABLED
-
ACTION_APPWIDGET_DISABLED
-
ACTION_APPWIDGET_OPTIONS_CHANGED
Создать макет виджета
Вы должны определить начальный макет для вашего виджета в XML и сохранить его в res/layout/
Directory проекта. См. Рекомендации по проектированию для получения подробной информации.
Создание макета виджетов просто, если вы знакомы с макетами . Тем не менее, имейте в виду, что макеты виджетов основаны на RemoteViews
, что не поддерживает каждый вид макета или виджета. Вы не можете использовать пользовательские представления или подклассы представлений, которые поддерживаются RemoteViews
.
RemoteViews
также поддерживает ViewStub
, который является невидимым, нулевым View
который вы можете использовать для лениво надувного ресурсов макета во время выполнения.
Поддержка поведения штата
Android 12 добавляет поддержку поведения состояния, используя следующие существующие компоненты:
Виджет по -прежнему без сохранения состояния. Ваше приложение должно хранить штат и зарегистрироваться для событий изменения штата.
В следующем примере кода показано, как реализовать эти компоненты.
Котлин
// 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 has 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) )
Ява
// 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 has 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));
Предоставьте два макета: одну целевую устройства, работающие на Android 12 или выше в res/layout-v31
, а также другие предыдущие предыдущие Android 11 или ниже в папке res/layout
по умолчанию.
Реализуйте округлые углы
Android 12 представляет следующие параметры системы, чтобы установить радиусы округлых углов вашего виджета:
system_app_widget_background_radius
: радиус углового фона виджета, который никогда не превышает 28 DP.system_app_widget_inner_radius
: радиус углового представления внутри виджет. Это ровно на 8 DP меньше, чем радиус фонового, чтобы хорошо выравниваться при использовании 8 DP.
В следующем примере показан виджет, в котором используется system_app_widget_background_radius
для угла виджета и system_app_widget_inner_radius
для представлений внутри виджета.
1 угол виджета.
2 уголка вида внутри виджет.
Важные соображения для округлых углов
- Сторонние пусковые установки и производители устройств могут переопределить параметр
system_app_widget_background_radius
, который будет меньше 28 DP. Параметрsystem_app_widget_inner_radius
всегда на 8 DP меньше, чем значениеsystem_app_widget_background_radius
. - Если ваш виджет не использует
@android:id/background
или определяет фон, который зажигает его контент на основе контура -true
android:clipToOutline
до 16 DP. См . Убедитесь, что ваш виджет совместим с Android 12 .
Для совместимости виджетов с предыдущими версиями Android мы рекомендуем определить пользовательские атрибуты и использовать пользовательскую тему, чтобы переопределить их для Android 12, как показано в следующем примере файлов XML:
/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" />