На этой странице описаны уточнения размеров виджетов и большая гибкость, представленные в Android 12 (уровень API 31). и определить размер виджета.
Используйте улучшенные API для размеров и макетов виджетов
Начиная с Android 12 (уровень API 31), вы можете задавать более точные атрибуты размера и гибкие макеты, выполнив следующие действия:
В предыдущих версиях Android можно было получить диапазоны размеров виджета с помощью дополнительных параметров OPTION_APPWIDGET_MIN_WIDTH, OPTION_APPWIDGET_MIN_HEIGHT, OPTION_APPWIDGET_MAX_WIDTH и OPTION_APPWIDGET_MAX_HEIGHT, а затем оценить размер виджета, но эта логика работает не во всех ситуациях. Для виджетов, предназначенных для Android 12 и более поздних версий, рекомендуем использовать адаптивные или точные макеты.
Как задать дополнительные ограничения на размер виджета
В Android 12 добавлены API, которые позволяют обеспечить более надежное масштабирование виджета на разных устройствах с разными размерами экрана.
Помимо существующих атрибутов minWidth, minHeight, minResizeWidth и minResizeHeight, используйте следующие новые атрибуты appwidget-provider:
targetCellWidthиtargetCellHeightопределяют целевой размер виджета в ячейках сетки панели запуска. Если они заданы, то используются вместо атрибутовminWidthиminHeight.maxResizeWidthиmaxResizeHeightопределяют максимальный размер, до которого панель запуска позволяет пользователю изменять размер виджета.
Ниже показано, как использовать атрибуты размера в XML.
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" android:targetCellWidth="3" android:targetCellHeight="2" android:maxResizeWidth="250dp" android:maxResizeHeight="110dp"> </appwidget-provider>
Предоставьте адаптивные макеты
Если макет должен меняться в зависимости от размера виджета, мы рекомендуем создать небольшой набор макетов, каждый из которых подходит для определенного диапазона размеров. Если это невозможно, можно предоставить макеты на основе точного размера виджета во время выполнения, как описано на этой странице.
Это позволяет более плавно масштабировать виджет и улучшает работу системы в целом, поскольку ей не нужно активировать приложение каждый раз, когда виджет отображается в другом размере.
В примере кода ниже показано, как предоставить список макетов.
override fun onUpdate( /* ... */ ) { val smallView = RemoteViews( /* ... */ ) val tallView = RemoteViews( /* ... */ ) val wideView = RemoteViews( /* ... */ ) val viewMapping: Map<SizeF, RemoteViews> = mapOf( SizeF(150f, 100f) to smallView, SizeF(150f, 200f) to tallView, SizeF(215f, 100f) to wideView ) val remoteViews = RemoteViews(viewMapping) appWidgetManager.updateAppWidget(id, remoteViews) }
Предположим, что у виджета есть следующие атрибуты:
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" android:minResizeWidth="160dp" android:minResizeHeight="110dp" android:maxResizeWidth="250dp" android:maxResizeHeight="200dp"> </appwidget-provider>
Приведенный выше фрагмент кода означает следующее:
smallViewподдерживает размеры от 160 dp (minResizeWidth) × 110 dp (minResizeHeight) до 160 dp × 199 dp (следующая точка отсечения – 1 dp).tallViewподдерживает размеры от 160 dp × 200 dp до 214 dp (следующая точка отсечения – 1) × 200 dp.wideViewподдерживает размеры от 215 dp × 110 dp (minResizeHeight) до 250 dp (maxResizeWidth) × 200 dp (maxResizeHeight).
Виджет должен поддерживать диапазон размеров от minResizeWidth × minResizeHeight до maxResizeWidth × maxResizeHeight. В пределах этого диапазона вы можете решить, в какой точке переключать макеты.
Предоставьте точные макеты
Если небольшой набор адаптивных макетов не подходит, вы можете предоставить разные макеты, адаптированные к размерам, в которых показывается виджет. Обычно это два размера для телефонов (вертикальный и горизонтальный режимы) и четыре размера для складных устройств.
Чтобы реализовать это решение, в приложении необходимо выполнить следующие действия:
Перегрузите метод
AppWidgetProvider.onAppWidgetOptionsChanged(), который вызывается при изменении набора размеров.Вызовите метод
AppWidgetManager.getAppWidgetOptions(), который возвращает объектBundleс размерами.Получите доступ к ключу
AppWidgetManager.OPTION_APPWIDGET_SIZESизBundle.
В примере кода ниже показано, как задать точные макеты.
override fun onAppWidgetOptionsChanged( context: Context, appWidgetManager: AppWidgetManager, id: Int, newOptions: Bundle? ) { super.onAppWidgetOptionsChanged(context, appWidgetManager, id, newOptions) // Get the new sizes. val sizes = newOptions?.let { BundleCompat.getParcelableArrayList( it, AppWidgetManager.OPTION_APPWIDGET_SIZES, SizeF::class.java ) } // Check that the list of sizes is provided by the launcher. if (sizes.isNullOrEmpty()) { return } // Map the sizes to the RemoteViews that you want. val remoteViews = RemoteViews(sizes.associateWith(::createRemoteViews)) appWidgetManager.updateAppWidget(id, remoteViews) } // Create the RemoteViews for the given size. private fun createRemoteViews(size: SizeF): RemoteViews { }
Как выбрать размер виджета
Для каждого виджета необходимо задать атрибуты targetCellWidth и targetCellHeight (для устройств с Android 12 или более поздней версией) или minWidth и minHeight (для всех версий Android), указывающие минимальный объем пространства, который он занимает по умолчанию. Однако когда пользователи добавляют виджет на главный экран, он обычно занимает больше места, чем указано в минимальных значениях.
Главные экраны Android предлагают пользователям сетку доступных пространств, на которых они могут размещать виджеты и значки. Размер сетки зависит от устройства. Например, на многих телефонах используется сетка 5 x 4, а на планшетах – сетка большего размера. При добавлении виджет растягивается, чтобы занять минимальное количество ячеек по горизонтали и вертикали, необходимое для соблюдения ограничений targetCellWidth и targetCellHeight на устройствах с Android 12 или более поздней версии или ограничений minWidth и minHeight на устройствах с Android 11 (уровень API 30) или более ранней версии.
Размеры ячеек и автоматические поля различаются на разных устройствах. В таблице ниже приведены минимальные размеры виджета на типичном телефоне с сеткой 5 x 4 в зависимости от количества занимаемых ячеек.
| Количество ячеек (ширина x высота) | Доступный размер в вертикальном режиме (dp) | Доступный размер в горизонтальном режиме (dp) |
|---|---|---|
| 1x1 | 57x102dp | 127x51dp |
| 2x1 | 130x102dp | 269x51dp |
| 3x1 | 203x102dp | 412x51dp |
| 4x1 | 276x102dp | 554x51dp |
| 5x1 | 349 x 102 dp | 697x51dp |
| 5x2 | 349x220dp | 697x117dp |
| 5x3 | 349x337dp | 697x184dp |
| 5x4 | 349x455dp | 697x250dp |
| … | … | … |
| n x m | (73n - 16) x (118m - 16) | (142n - 15) x (66m - 15) |
Размеры ячеек в вертикальном режиме определяют значения атрибутов minWidth, minResizeWidth и maxResizeWidth. Аналогично, размеры ячеек в горизонтальном режиме определяют значения атрибутов minHeight, minResizeHeight и maxResizeHeight.
Это связано с тем, что ширина ячейки обычно меньше в портретном режиме, чем в ландшафтном, и, аналогично, высота ячейки обычно меньше в ландшафтном режиме, чем в портретном.
Например, если вы хотите, чтобы ширину виджета можно было уменьшить до одной ячейки на Google Pixel 4, вам нужно установить для minResizeWidth значение не более 56 dp, чтобы значение атрибута minResizeWidth было меньше 57 dp, поскольку ширина ячейки в портретном режиме составляет не менее 57 dp.
Аналогично, если вы хотите, чтобы высота виджета изменялась в пределах одной ячейки на том же устройстве, вам необходимо установить для minResizeHeight значение не более 50 dp, чтобы значение атрибута minResizeHeight было меньше 51 dp, поскольку высота одной ячейки в горизонтальном режиме составляет не менее 51 dp.
Размер каждого виджета можно менять в пределах, заданных атрибутами minResizeWidth/minResizeHeight и maxResizeWidth/maxResizeHeight. Это значит, что виджет должен адаптироваться к любому размеру в этом диапазоне.
Например, чтобы задать размер виджета по умолчанию, можно использовать следующие атрибуты:
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" android:targetCellWidth="3" android:targetCellHeight="2" android:minWidth="180dp" android:minHeight="110dp"> </appwidget-provider>
Это означает, что размер виджета по умолчанию составляет 3 x 2 ячейки, как указано в атрибутах targetCellWidth и targetCellHeight, или 180 x 110 dp, как указано в атрибутах minWidth и minHeight для устройств с Android 11 или более ранней версии. В последнем случае размер в ячейках может варьироваться в зависимости от устройства.
Чтобы задать поддерживаемые диапазоны размеров виджета, можно использовать следующие атрибуты:
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" android:minResizeWidth="180dp" android:minResizeHeight="110dp" android:maxResizeWidth="530dp" android:maxResizeHeight="450dp"> </appwidget-provider>
Как указано в предыдущих атрибутах, ширину виджета можно изменить со 180 dp до 530 dp, а высоту – со 110 dp до 450 dp. Размер виджета можно изменить с 3 x 2 до 5 x 2 ячеек, если выполняются следующие условия:
- На устройстве используется сетка 5 x 4.
- Сопоставление количества ячеек и доступного размера в dp выполняется в соответствии с таблицей, в которой показаны приблизительные минимальные размеры на этой странице.
- Виджет адаптируется к этому диапазону размеров.
val smallView = RemoteViews(context.packageName, R.layout.widget_weather_forecast_small) val mediumView = RemoteViews(context.packageName, R.layout.widget_weather_forecast_medium) val largeView = RemoteViews(context.packageName, R.layout.widget_weather_forecast_large) val viewMapping: Map<SizeF, RemoteViews> = mapOf( SizeF(180f, 110f) to smallView, SizeF(270f, 110f) to mediumView, SizeF(270f, 280f) to largeView ) appWidgetManager.updateAppWidget(appWidgetId, RemoteViews(viewMapping))
Предположим, что виджет использует адаптивные макеты, определенные в предыдущих фрагментах кода. Это означает, что макет, указанный как R.layout.widget_weather_forecast_small, используется для размеров от 180 dp (minResizeWidth) x 110 dp (minResizeHeight) до 269 x 279 dp (следующие пороговые значения минус 1). Аналогично, R.layout.widget_weather_forecast_medium используется для размеров от 270 x 110 dp до 270 x 279 dp, а R.layout.widget_weather_forecast_large – для размеров от 270 x 280 dp до 530 dp (maxResizeWidth) x 450 dp (maxResizeHeight).
По мере того как пользователь изменяет размер виджета, его внешний вид адаптируется к каждому размеру ячеек, как показано в следующих примерах.
R.layout.widget_weather_forecast_small.
R.layout.widget_weather_forecast_medium.
R.layout.widget_weather_forecast_medium.
R.layout.widget_weather_forecast_large.
R.layout.widget_weather_forecast_large.