Widżety aplikacji to miniaturowe widoki aplikacji, które możesz umieszczać w innych aplikacjach, np. na ekranie głównym, i otrzymywać okresowe aktualizacje. Te widoki są w interfejsie nazywane widgetami. Możesz opublikować widget za pomocą dostawcy widgetów aplikacji (lub dostawcy widgetów). Składnik aplikacji, który zawiera inne widżety, nazywa się hostem widżetów aplikacji (lub hostem widżetów). Ilustracja 1 przedstawia przykładowy widżet muzyczny:

Z tego dokumentu dowiesz się, jak opublikować widżet za pomocą dostawcy widżetów. Więcej informacji o tworzeniu własnego AppWidgetHost
do hostowania widżetów aplikacji znajdziesz w artykule Tworzenie hosta widżetów.
Informacje o projektowaniu widżetu znajdziesz w artykule Omówienie widżetów aplikacji.
Komponenty widżetu
Aby utworzyć widżet, potrzebujesz tych podstawowych komponentów:
- Obiekt
AppWidgetProviderInfo
- Opisuje metadane widżetu, takie jak jego układ, częstotliwość aktualizacji i klasa
AppWidgetProvider
.AppWidgetProviderInfo
jest zdefiniowany w XML, zgodnie z opisem w tym dokumencie. AppWidgetProvider
zajęcia- Określa podstawowe metody, które umożliwiają programowe korzystanie z widżetu. Dzięki niemu otrzymujesz transmisje, gdy widżet jest aktualizowany, włączany, wyłączany lub usuwany. Deklarujesz interfejs
AppWidgetProvider
w pliku manifestu, a następnie implementujesz go zgodnie z opisem w tym dokumencie. - Wyświetlanie układu
- Określa początkowy układ widżetu. Układ jest zdefiniowany w XML, jak opisano w tym dokumencie.
Ilustracja 2 pokazuje, jak te komponenty pasują do ogólnego procesu przetwarzania widżetów aplikacji.

Jeśli widżet aplikacji wymaga konfiguracji przez użytkownika, zaimplementuj aktywność konfiguracji widżetu aplikacji. Ta aktywność umożliwia użytkownikom modyfikowanie ustawień widżetów, np. strefy czasowej widżetu zegara.
- Od Androida 12 (poziom API 31) możesz udostępniać domyślną konfigurację i pozwalać użytkownikom na późniejsze ponowne skonfigurowanie widżetu. Więcej informacji znajdziesz w artykułach Korzystanie z domyślnej konfiguracji widżetu i Umożliwianie użytkownikom ponownej konfiguracji umieszczonych widżetów.
- W Androidzie 11 (poziom interfejsu API 30) lub starszym ta aktywność jest uruchamiana za każdym razem, gdy użytkownik doda widżet do ekranu głównego.
Zalecamy też wprowadzenie tych ulepszeń: elastyczne układy widżetów, różne ulepszenia, zaawansowane widżety, widżety kolekcji i tworzenie hosta widżetów.
Zadeklaruj plik XML AppWidgetProviderInfo
Obiekt AppWidgetProviderInfo
określa podstawowe cechy widżetu.
Zdefiniuj obiekt AppWidgetProviderInfo
w pliku zasobu XML za pomocą pojedynczego elementu <appwidget-provider>
i zapisz go w folderze res/xml/
projektu.
Pokazuje to poniższy przykład:
<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>
Atrybuty rozmiaru widżetu
Domyślny ekran główny umieszcza widżety w swoim oknie na podstawie siatki komórek o określonej wysokości i szerokości. Większość ekranów głównych pozwala widżetom zajmować rozmiary będące wielokrotnościami komórek siatki, np. 2 komórki w poziomie i 3 w pionie.
Atrybuty rozmiaru widżetu umożliwiają określenie domyślnego rozmiaru widżetu oraz podanie dolnej i górnej granicy jego rozmiaru. W tym kontekście domyślny rozmiar widżetu to rozmiar, jaki widżet przyjmuje po pierwszym dodaniu go do ekranu głównego.
W tej tabeli opisujemy atrybuty <appwidget-provider>
dotyczące rozmiaru widżetu:
Atrybuty i opis | |
---|---|
targetCellWidth i targetCellHeight (Android 12),minWidth i minHeight |
targetCellWidth i targetCellHeight oraz minWidth i minHeight , aby aplikacja mogła używać atrybutów minWidth i minHeight , jeśli urządzenie użytkownika nie obsługuje atrybutów targetCellWidth i targetCellHeight . Jeśli są obsługiwane, atrybuty targetCellWidth i targetCellHeight mają pierwszeństwo przed atrybutami minWidth i minHeight .
|
minResizeWidth i
minResizeHeight |
Określ bezwzględnie minimalny rozmiar widżetu. Te wartości określają rozmiar, poniżej którego widżet jest nieczytelny lub w inny sposób nieużyteczny. Użycie tych atrybutów umożliwia użytkownikowi zmianę rozmiaru widżetu na mniejszy niż domyślny. Atrybut minResizeWidth jest ignorowany, jeśli jest większy niż minWidth lub jeśli nie jest włączona zmiana rozmiaru w poziomie. Zobacz resizeMode . Podobnie atrybut
minResizeHeight jest ignorowany, jeśli jest większy niż
minHeight lub jeśli nie jest włączona zmiana rozmiaru w pionie. |
maxResizeWidth i
maxResizeHeight |
Określ zalecany maksymalny rozmiar widżetu. Jeśli wartości nie są wielokrotnością wymiarów komórki siatki, są zaokrąglane w górę do najbliższego rozmiaru komórki. Atrybut maxResizeWidth jest ignorowany, jeśli jest mniejszy niż minWidth lub jeśli nie jest włączona zmiana rozmiaru w poziomie. Zobacz resizeMode . Podobnie atrybut maxResizeHeight jest ignorowany, jeśli jest większy niż minHeight lub jeśli nie jest włączona zmiana rozmiaru w pionie.
Wprowadzono w Androidzie 12. |
resizeMode |
Określa reguły, według których można zmieniać rozmiar widżetu. Za pomocą tego atrybutu możesz zmieniać rozmiar widżetów na ekranie głównym w pionie, w poziomie lub w obu kierunkach. Użytkownicy naciskają i przytrzymują widżet, aby wyświetlić uchwyty zmiany rozmiaru, a następnie przeciągają uchwyty poziome lub pionowe, aby zmienić rozmiar widżetu w siatce układu. Wartości atrybutu resizeMode to horizontal , vertical i none . Aby zadeklarować, że rozmiar widżetu można zmieniać w pionie i poziomie, użyj horizontal|vertical . |
Przykład
Aby pokazać, jak atrybuty z tabeli powyżej wpływają na rozmiar widżetu, przyjmijmy te specyfikacje:
- Komórka siatki ma 30 dp szerokości i 50 dp wysokości.
- Podajemy specyfikację tego atrybutu:
<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" />
Od Androida 12:
Użyj atrybutów targetCellWidth
i targetCellHeight
jako domyślnego rozmiaru widżetu.
Domyślny rozmiar widżetu to 2x2. Rozmiar widżetu można zmniejszyć do 2x1 lub zwiększyć do 4x3.
Android 11 i starsze:
Do obliczania domyślnego rozmiaru widżetu używaj atrybutów minWidth
i minHeight
.
Domyślna szerokość = Math.ceil(80 / 30)
= 3
Wysokość domyślna = Math.ceil(80 / 50)
= 2
Domyślny rozmiar widżetu to 3x2. Rozmiar widżetu można zmniejszyć do 2x1 lub zwiększyć do pełnego ekranu.
Dodatkowe atrybuty widżetu
W tej tabeli opisujemy atrybuty <appwidget-provider>
dotyczące cech innych niż rozmiar widżetu.
Atrybuty i opis | |
---|---|
updatePeriodMillis |
Określa, jak często platforma widżetów wysyła żądanie aktualizacji do AppWidgetProvider , wywołując metodę zwrotną onUpdate() . Aktualizacja nie musi nastąpić dokładnie o podanej godzinie. Aby oszczędzać baterię, zalecamy aktualizowanie tak rzadko, jak to możliwe – nie częściej niż raz na godzinę.
Pełną listę kwestii, które należy wziąć pod uwagę przy wyborze odpowiedniego okresu aktualizacji, znajdziesz w artykule Optymalizacje aktualizacji treści widżetu. |
initialLayout |
Wskazuje zasób układu, który określa układ widżetu. |
configure |
Określa aktywność, która jest uruchamiana, gdy użytkownik doda widżet, umożliwiając mu skonfigurowanie właściwości widżetu. Zobacz Umożliwianie użytkownikom konfigurowania widżetów. Od Androida 12 aplikacja może pominąć początkową konfigurację. Szczegółowe informacje znajdziesz w artykule Używanie domyślnej konfiguracji widżetu. |
description |
Określa opis selektora widżetów, który ma się wyświetlać w przypadku Twojego widżetu. Wprowadzono w Androidzie 12. |
previewLayout (Android 12) i previewImage (Android 11 i starsze) |
previewImage i previewLayout , aby w przypadku, gdy urządzenie użytkownika nie obsługuje atrybutu previewLayout , aplikacja mogła używać atrybutu previewImage . Więcej informacji znajdziesz w artykule Wsteczna zgodność ze skalowalnymi podglądami widżetów.
|
autoAdvanceViewId |
Określa identyfikator widoku podrzędnego widżetu, który jest automatycznie przewijany przez hosta widżetu. |
widgetCategory |
Określa, czy widżet może być wyświetlany na ekranie głównym (home_screen ), ekranie blokady (keyguard ) czy na obu tych ekranach. W przypadku Androida 5.0 i nowszych wersji obowiązuje tylko home_screen .
|
widgetFeatures |
Deklaruje funkcje obsługiwane przez widżet. Jeśli na przykład chcesz, aby widżet używał domyślnej konfiguracji, gdy użytkownik go doda, określ flagi configuration_optional i reconfigurable . Dzięki temu po dodaniu widżetu przez użytkownika nie będzie uruchamiana aktywność konfiguracyjna. Użytkownik może później ponownie skonfigurować widżet. |
Używanie klasy AppWidgetProvider do obsługi transmisji widżetów
Klasa AppWidgetProvider
obsługuje transmisje widżetów i aktualizuje widżet w odpowiedzi na zdarzenia cyklu życia widżetu. W sekcjach poniżej znajdziesz informacje o tym, jak zadeklarować AppWidgetProvider
w pliku manifestu, a potem wdrożyć tę funkcję.
Deklarowanie widżetu w pliku manifestu
Najpierw zadeklaruj klasę AppWidgetProvider
w pliku AndroidManifest.xml
aplikacji, jak pokazano w tym przykładzie:
<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>
Element <receiver>
wymaga atrybutu android:name
, który określa AppWidgetProvider
używany przez widżet. Komponent nie może być eksportowany, chyba że osobny proces musi wysyłać transmisję do Twojego AppWidgetProvider
, co zwykle nie ma miejsca.
Element <intent-filter>
musi zawierać element <action>
z atrybutem android:name
. Ten atrybut określa, że AppWidgetProvider
akceptuje
ACTION_APPWIDGET_UPDATE
transmisję. Jest to jedyna transmisja, którą musisz wyraźnie zadeklarować. AppWidgetManager
automatycznie wysyła wszystkie inne transmisje widżetów do AppWidgetProvider
w razie potrzeby.
Element <meta-data>
określa zasób AppWidgetProviderInfo
i wymaga tych atrybutów:
android:name
: określa nazwę metadanych. Użyj znakuandroid.appwidget.provider
, aby zidentyfikować dane jako deskryptorAppWidgetProviderInfo
.android:resource
: określa lokalizację zasobuAppWidgetProviderInfo
.
Implementowanie klasy AppWidgetProvider
Klasa AppWidgetProvider
rozszerza BroadcastReceiver
jako klasa pomocnicza do obsługi transmisji widżetów. Otrzymuje tylko transmisje zdarzeń, które są istotne dla widżetu, np. gdy widżet jest aktualizowany, usuwany, włączany lub wyłączany. Gdy wystąpią te zdarzenia transmisji, wywoływane są te metody:AppWidgetProvider
onUpdate()
- Ta funkcja jest wywoływana w celu aktualizowania widżetu w interwałach zdefiniowanych przez atrybut
updatePeriodMillis
w elemencieAppWidgetProviderInfo
. Więcej informacji znajdziesz w tabeli opisującej dodatkowe atrybuty widżetu na tej stronie. - Ta metoda jest też wywoływana, gdy użytkownik dodaje widżet, więc wykonuje niezbędne czynności konfiguracyjne, takie jak definiowanie procedur obsługi zdarzeń dla obiektów
View
lub uruchamianie zadań wczytywania danych do wyświetlenia w widżecie. Jeśli jednak zadeklarujesz działanie konfiguracyjne bez flagiconfiguration_optional
, ta metoda nie jest wywoływana, gdy użytkownik dodaje widżet, ale jest wywoływana w przypadku kolejnych aktualizacji. Za przeprowadzenie pierwszej aktualizacji po zakończeniu konfiguracji odpowiada działanie konfiguracji. Więcej informacji znajdziesz w artykule Umożliwianie użytkownikom konfigurowania widżetów aplikacji. - Najważniejszym wywołaniem zwrotnym jest
onUpdate()
. Więcej informacji znajdziesz w sekcji Obsługa zdarzeń za pomocą klasyonUpdate()
na tej stronie .
onAppWidgetOptionsChanged()
Jest ona wywoływana, gdy widżet jest umieszczany po raz pierwszy i za każdym razem, gdy jest zmieniany jego rozmiar. Użyj tego wywołania zwrotnego, aby wyświetlać lub ukrywać treści w zależności od zakresów rozmiarów widżetu. Zakresy rozmiarów, a od Androida 12 także listę możliwych rozmiarów, jakie może przyjąć instancja widżetu, możesz uzyskać, wywołując
getAppWidgetOptions()
. Zwraca ona obiektBundle
, który zawiera te elementy:OPTION_APPWIDGET_MIN_WIDTH
: zawiera dolną granicę szerokości instancji widżetu w jednostkach dp.OPTION_APPWIDGET_MIN_HEIGHT
: zawiera dolną granicę wysokości instancji widżetu w jednostkach dp.OPTION_APPWIDGET_MAX_WIDTH
: zawiera górną granicę szerokości instancji widżetu w jednostkach dp.OPTION_APPWIDGET_MAX_HEIGHT
: zawiera górną granicę wysokości instancji widżetu w jednostkach dp.OPTION_APPWIDGET_SIZES
: zawiera listę możliwych rozmiarów (List<SizeF>
) w jednostkach dp, które może przyjąć instancja widżetu. Wprowadzono w Androidzie 12.
onDeleted(Context, int[])
Jest ona wywoływana za każdym razem, gdy widżet zostanie usunięty z hosta widżetów.
onEnabled(Context)
Jest wywoływana, gdy instancja widżetu jest tworzona po raz pierwszy. Jeśli na przykład użytkownik doda 2 instancje widżetu, wywołanie nastąpi tylko za pierwszym razem. Jeśli musisz otworzyć nową bazę danych lub przeprowadzić inną konfigurację, która musi zostać wykonana tylko raz dla wszystkich instancji widżetu, to jest to dobre miejsce na to.
onDisabled(Context)
Ta metoda jest wywoływana, gdy ostatnia instancja widżetu zostanie usunięta z hosta widżetu. W tym miejscu możesz usunąć wszystkie zadania wykonane w
onEnabled(Context)
, np. usunąć tymczasową bazę danych.onReceive(Context, Intent)
Jest ona wywoływana w przypadku każdej transmisji i przed każdą z poprzednich metod wywołania zwrotnego. Zwykle nie musisz implementować tej metody, ponieważ domyślna implementacja
AppWidgetProvider
filtruje wszystkie transmisje widżetów i w odpowiedni sposób wywołuje poprzednie metody.
Musisz zadeklarować implementację klasy AppWidgetProvider
jako odbiornik transmisji za pomocą elementu <receiver>
w pliku AndroidManifest
. Więcej informacji znajdziesz w sekcji Deklarowanie widżetu w pliku manifestu na tej stronie.
Obsługa zdarzeń za pomocą klasy onUpdate()
Najważniejszym wywołaniem zwrotnym AppWidgetProvider
jest onUpdate()
, ponieważ jest ono wywoływane, gdy każdy widżet jest dodawany do hosta, chyba że używasz aktywności konfiguracyjnej bez flagi configuration_optional
. Jeśli widżet akceptuje zdarzenia interakcji użytkownika, zarejestruj w tym wywołaniu zwrotnym moduły obsługi zdarzeń. Jeśli widżet nie tworzy plików tymczasowych ani baz danych ani nie wykonuje innych działań, które wymagają czyszczenia, onUpdate()
może być jedyną metodą wywołania zwrotnego, którą musisz zdefiniować.
Jeśli na przykład chcesz utworzyć widżet z przyciskiem, który po kliknięciu uruchamia aktywność, możesz użyć tej implementacji AppWidgetProvider
:
Kotlin
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) } } }
Java
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); } } }
Ten AppWidgetProvider
definiuje tylko metodę onUpdate()
, używając jej do utworzenia elementu PendingIntent
, który uruchamia element Activity
i dołącza go do przycisku widżetu za pomocą metody setOnClickPendingIntent(int,
PendingIntent)
. Zawiera pętlę, która iteruje przez każdy wpis w appWidgetIds
, czyli tablicy identyfikatorów, które identyfikują każdy widżet utworzony przez tego dostawcę. Jeśli użytkownik utworzy więcej niż 1 instancję widżetu, wszystkie będą aktualizowane jednocześnie. Jednak w przypadku wszystkich instancji widżetu zarządza się tylko 1 harmonogram updatePeriodMillis
. Jeśli np. harmonogram aktualizacji jest ustawiony na co 2 godziny, a drugi egzemplarz widżetu zostanie dodany godzinę po pierwszym, oba będą aktualizowane w okresie zdefiniowanym przez pierwszy, a drugi okres aktualizacji zostanie zignorowany. Obie aktualizują się co 2 godziny, a nie co godzinę.
Więcej informacji znajdziesz w ExampleAppWidgetProvider.java
przykładowej klasie.
Otrzymywanie intencji rozgłaszania widżetu
AppWidgetProvider
to klasa ułatwiająca. Jeśli chcesz otrzymywać transmisje widżetu bezpośrednio, możesz zaimplementować własną funkcję BroadcastReceiver
lub zastąpić wywołanie zwrotne onReceive(Context,Intent)
. Intencje, na które musisz zwrócić uwagę, to:
ACTION_APPWIDGET_UPDATE
ACTION_APPWIDGET_DELETED
ACTION_APPWIDGET_ENABLED
ACTION_APPWIDGET_DISABLED
ACTION_APPWIDGET_OPTIONS_CHANGED
Tworzenie układu widżetu
Musisz zdefiniować początkowy układ widżetu w pliku XML i zapisać go w katalogu res/layout/
projektu. Szczegółowe informacje znajdziesz w wytycznych dotyczących projektowania.
Tworzenie układu widżetu jest proste, jeśli znasz układy. Pamiętaj jednak, że układy widżetów są oparte na RemoteViews
, które nie obsługuje wszystkich rodzajów układów ani widżetów widoku. Nie możesz używać widoków niestandardowych ani podklas widoków obsługiwanych przez RemoteViews
.
RemoteViews
obsługuje też ViewStub
, czyli niewidoczny element View
o rozmiarze zero, którego możesz używać do leniwego powiększania zasobów układu w czasie działania.
Obsługa zachowań stanowych
W Androidzie 12 dodano obsługę zachowań stanowych przy użyciu tych komponentów:
Widżet nadal nie ma stanu. Aplikacja musi przechowywać stan i rejestrować zdarzenia zmiany stanu.

Poniższy przykład kodu pokazuje, jak wdrożyć te komponenty.
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 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) )
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 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));
Podaj 2 układy: jeden dla urządzeń z Androidem 12 lub nowszym w folderze res/layout-v31
, a drugi dla urządzeń z Androidem 11 lub starszym w domyślnym folderze res/layout
.
Implementowanie zaokrąglonych narożników
Android 12 wprowadza te parametry systemowe, które umożliwiają ustawianie promieni zaokrąglonych rogów widżetu:
system_app_widget_background_radius
: promień zaokrąglenia tła widżetu, który nigdy nie jest większy niż 28 dp.Promień wewnętrzny, który można obliczyć na podstawie promienia zewnętrznego i wypełnienia. Przyjrzyj się temu fragmentowi kodu:
/** * Applies corner radius for views that are visually positioned [widgetPadding]dp inside of the * widget background. */ @Composable fun GlanceModifier.appWidgetInnerCornerRadius(widgetPadding: Dp): GlanceModifier { if (Build.VERSION.SDK_INT < 31) { return this } val resources = LocalContext.current.resources // get dimension in float (without rounding). val px = resources.getDimension(android.R.dimen.system_app_widget_background_radius) val widgetBackgroundRadiusDpValue = px / resources.displayMetrics.density if (widgetBackgroundRadiusDpValue < widgetPadding.value) { return this } return this.cornerRadius(Dp(widgetBackgroundRadiusDpValue - widgetPadding.value)) }
Aby obliczyć odpowiedni promień wewnętrznej części widżetu, użyj tego wzoru: systemRadiusValue - widgetPadding
Widżety, które przycinają swoje treści do kształtów innych niż prostokątne, powinny używać identyfikatora widoku @android:id/background
jako identyfikatora widoku tła, w którym parametr android:clipToOutline
ma wartość true
.
Ważne uwagi dotyczące zaokrąglonych rogów
- Launchery innych firm i producenci urządzeń mogą zastąpić parametr
system_app_widget_background_radius
wartością mniejszą niż 28 dp. Jeśli widżet nie używa
@android:id/background
ani nie definiuje tła, które przycina jego zawartość na podstawie konturu – z ustawieniemandroid:clipToOutline
natrue
– program uruchamiający automatycznie identyfikuje tło i przycina widżet za pomocą prostokąta z zaokrąglonymi rogami ustawionego na promień systemowy.Kształty inne niż prostokątne muszą mieścić się w zaokrąglonym prostokątnym kontenerze zmiany rozmiaru, aby nie zostały przycięte.
Od Androida 16 wartość systemowa AOSP dla parametru
system_app_widget_background_radius
to24dp
. Programy uruchamiające i producenci urządzeń mogą przycinać widżet dosystem_app_widget_background_radius
.Wewnętrzna zawartość widżetu musi mieć wystarczające dopełnienie, aby obsługiwać wartości promienia
system_app_widget_background_radius
do28dp
. Dzięki temu unikniesz przycinania treści przez zaokrąglone rogi.
Aby zapewnić zgodność widżetu z poprzednimi wersjami Androida, zalecamy zdefiniowanie atrybutów niestandardowych i użycie niestandardowego motywu do zastąpienia ich w Androidzie 12, jak pokazano w tych przykładowych plikach 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" />