Tworzenie prostego widżetu

Widżety aplikacji to miniatury aplikacji, które możesz umieszczać w innych aplikacjach (np. na ekranie głównym) i regularnie aktualizować. W interfejsie te widoki są nazywane widżetami. Możesz opublikować jeden z nich za pomocą dostawcy widżetów aplikacji (czyli dostawcy widżetów). Składnik aplikacji, który zawiera inne widżety, nazywa się hostem widżetu aplikacji (lub hostem widżetu). Rysunek 1 pokazuje przykładowy widżet muzyczny:

Przykład widżetu muzycznego
Rysunek 1. Przykład widżetu muzycznego

Z tego dokumentu dowiesz się, jak opublikować widżet za pomocą dostawcy widżetów. Szczegółowe informacje o tworzeniu własnych AppWidgetHost do hostowania widżetów aplikacji znajdziesz w artykule Tworzenie hosta widżetów.

Informacje o projektowaniu widżetów znajdziesz w artykule Przegląd widżetów aplikacji.

Komponenty widżetu

Aby utworzyć widżet, potrzebujesz tych podstawowych komponentów:

AppWidgetProviderInfo obiekt
Opisuje metadane widżetu, takie jak układ, częstotliwość aktualizacji i klasa AppWidgetProvider. Wartość AppWidgetProviderInfo jest zdefiniowana w pliku XML zgodnie z opisem w tym dokumencie.
AppWidgetProvider zajęcia
Określa podstawowe metody, które umożliwiają programowe tworzenie interfejsu z widżetem. Dzięki niemu otrzymujesz powiadomienia, gdy widżet zostanie zaktualizowany, włączony, wyłączony lub usunięty. Zadeklaruj AppWidgetProvider w pliku manifestu, a następnie wdróż go zgodnie z opisem w tym dokumencie.
Wyświetlanie układu
Określa początkowy układ widżetu. Układ jest zdefiniowany w formacie XML, zgodnie z opisem w tym dokumencie.

Na rysunku 2 widać, jak te komponenty pasują do ogólnego przepływu danych w przypadku widżetów aplikacji.

Przetwarzanie widżetu aplikacji
Rysunek 2. Przetwarzanie widżetu aplikacji

Jeśli widżet wymaga konfiguracji przez użytkownika, zaimplementuj odpowiednią aktywność. Ta aktywność umożliwia użytkownikom modyfikowanie ustawień widżetów, np. strefy czasowej w widżecie zegara.

Polecamy też te usprawnienia: elastyczne układy widżetów, różne ulepszenia, zaawansowane widżety, widżety kolekcjitworzenie hosta widżetów.

Zadeklaruj plik XML AppWidgetProviderInfo

Obiekt AppWidgetProviderInfo definiuje najważniejsze cechy widżetu. Zdefiniuj obiekt AppWidgetProviderInfo w pliku zasobu XML, używając pojedynczego elementu <appwidget-provider>, i zapisz go w folderze res/xml/ projektu.

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 widgeta

Domyślny ekran główny umieszcza widżety w oknie na podstawie siatki komórek o określonej wysokości i szerokości. Większość ekranów głównych pozwala na umieszczanie widżetów o rozmiarze będącym wielokrotnością liczby całkowitej komórek siatki – na przykład 2 komórki w poziomie i 3 komórki w pionie.

Atrybuty rozmiaru widżetu umożliwiają określenie domyślnego rozmiaru widżetu oraz podanie dolnego i górnego limitu rozmiaru. W tym kontekście domyślny rozmiar widżetu to rozmiar, który widżet ma, gdy jest po raz pierwszy dodawany do ekranu głównego.

W tej tabeli opisano atrybuty <appwidget-provider> dotyczące rozmiaru widgeta:

Atrybuty i opis
targetCellWidthtargetCellHeight (Android 12), minWidthminHeight
  • Od Androida 12 atrybuty targetCellWidthtargetCellHeight określają domyślny rozmiar widgeta w celu określenia komórek siatki. Te atrybuty ignorowane w Androidzie 11 i starszych wersjach, a mogą być ignorowane, jeśli ekran główny nie obsługuje układu siatki.
  • Atrybuty minWidthminHeight określają domyślny rozmiar widgeta w dp. Jeśli wartości minimalnej szerokości lub wysokości widżetu nie pasują do wymiarów komórek, wartości są zaokrąglane w górę do najbliższego rozmiaru komórki.
Zalecamy określenie obu zestawów atrybutów: targetCellWidthtargetCellHeight oraz minWidthminHeight, aby aplikacja mogła użyć atrybutów minWidthminHeight, jeśli urządzenie użytkownika nie obsługuje atrybutów targetCellWidthtargetCellHeight. Jeśli są obsługiwane, atrybuty targetCellWidth i targetCellHeight mają pierwszeństwo przed atrybutami minWidth i minHeight.
minResizeWidth i minResizeHeight Określ bezwzględny minimalny rozmiar widżetu. Te wartości określają rozmiar, przy którym widżet jest niewyraźny lub nieużyteczny. Korzystanie z 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łączone poziome dostosowywanie rozmiaru. Zobacz resizeMode. Podobnie atrybut minResizeHeight jest ignorowany, jeśli jest większy niż minHeight lub jeśli nie jest włączone skalowanie pionowe.
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łączone poziome dostosowywanie rozmiaru. Zobacz resizeMode. Podobnie atrybut maxResizeHeight jest ignorowany, jeśli jest większy niż minHeight lub jeśli nie jest włączone skalowanie pionowe. Wprowadzone w Androidzie 12.
resizeMode Określa reguły, według których można zmieniać rozmiar widżetu. Za pomocą tego atrybutu możesz zmienić rozmiar widżetów na ekranie głównym w układzie poziomym, pionowym lub obu tych osiach. Użytkownicy mogą nacisnąć i przytrzymać widżet, aby wyświetlić uchwyty do zmiany rozmiaru, a potem przeciągnąć uchwyty poziome lub pionowe, aby zmienić jego rozmiar na siatce układu. Wartości atrybutu resizeMode to horizontal, vertical i none. Aby zadeklarować, że rozmiar widżetu można zmieniać w poziomie i w pionie, użyj:horizontal|vertical.

Przykład

Aby zilustrować, jak atrybuty z poprzedniej tabeli wpływają na rozmiar widżetu, załóżmy następujące specyfikacje:

  • Komórka siatki ma 30 dp szerokości i 50 dp wysokości.
  • Oto specyfikacja 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" />

Począwszy od Androida 12:

Użyj atrybutów targetCellWidthtargetCellHeight jako domyślnego rozmiaru widgeta.

Domyślny rozmiar widżetu to 2 x 2. Rozmiar widżetu można zmienić na 2 x 1 lub 4 x 3.

Android 11 i starsze:

Użyj atrybutów minWidth i minHeight, aby obliczyć domyślny rozmiar widgeta.

Domyślna szerokość = Math.ceil(80 / 30) = 3

Domyślna wysokość = Math.ceil(80 / 50) = 2

Domyślny rozmiar widżetu to 3 x 2. Rozmiar widżetu można zmienić na 2 x 1 lub na pełny ekran.

Dodatkowe atrybuty widżetu

W tej tabeli opisano atrybuty <appwidget-provider> dotyczące właściwości innych niż rozmiary widgetów.

Atrybuty i opis
updatePeriodMillis Określa, jak często platforma widżetu prosi o aktualizację AppWidgetProvider, wywołując metodę wywołania zwrotnego onUpdate(). Nie możemy zagwarantować, że aktualizacja nastąpi dokładnie w tym czasie. Zalecamy jak najrzadsze aktualizowanie (nie częściej niż raz na godzinę), aby oszczędzać baterię. Pełną listę czynników, które należy wziąć pod uwagę przy wyborze odpowiedniego okresu aktualizacji, znajdziesz w artykule Optymalizacja aktualizacji treści widgetów.
initialLayout Wskazuje zasób układu, który definiuje układ widżetu.
configure Określa aktywność, która uruchamia się, gdy użytkownik doda widżet, umożliwiając mu skonfigurowanie jego właściwości. Zapoznaj się z artykułem Umożliwienie użytkownikom konfigurowania widżetów. Od Androida 12 aplikacja może pominąć początkową konfigurację. Więcej informacji znajdziesz w sekcji Używanie domyślnej konfiguracji widżetu.
description Określa opis selektora widżetu, który ma być wyświetlany w przypadku Twojego widżetu. Wprowadzone w Androidzie 12.
previewLayout (Android 12) i previewImage (Android 11 i starsze)
  • Od Androida 12 atrybut previewLayout określa skalowalny podgląd, który dostarczasz jako układ XML ustawiony na domyślny rozmiar widżetu. W idealnej sytuacji XML układu określony w tym atrybucie powinien być taki sam jak XML układu w przypadku rzeczywistego widgeta z realistycznymi wartościami domyślnymi.
  • W Androidzie 11 lub starszym atrybut previewImageokreśla podgląd wyglądu widżetu po skonfigurowaniu, który użytkownik widzi podczas wybierania widżetu aplikacji. Jeśli nie prześlesz ikony, użytkownik zobaczy ikonę programu uruchamiającego Twoją aplikację. To pole odpowiada atrybucie android:previewImage w elemencie <receiver> w pliku AndroidManifest.xml.
Uwaga: zalecamy określenie atrybutów previewImagepreviewLayout, aby aplikacja mogła użyć atrybutu previewImage, jeśli urządzenie użytkownika nie obsługuje atrybutu previewLayout. Więcej informacji znajdziesz w artykule Wsteczna zgodność z przewidywanymi podglądami widżetów skalowanych.
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. W przypadku Androida 5.0 lub nowszego prawidłowa jest tylko wartość home_screen.
widgetFeatures Deklaruje funkcje obsługiwane przez widżet. Jeśli na przykład chcesz, aby widget używał domyślnej konfiguracji po dodaniu przez użytkownika, określ flagi configuration_optional i reconfigurable. Dzięki temu nie trzeba uruchamiać czynności konfiguracyjnej po dodaniu widżetu przez użytkownika. Użytkownik może później ponownie skonfigurować widget.

Obsługa transmisji widżetów za pomocą klasy AppWidgetProvider

Klasa AppWidgetProvider obsługuje transmisje danych z widżetów i aktualizuje widżet w odpowiedzi na zdarzenia cyklu życia widżetu. W następnych sekcjach znajdziesz informacje o deklarowaniu AppWidgetProvider w pliku manifestu i jego implementowaniu.

Zadeklaruj widżet w pliku manifestu

Najpierw zadeklaruj klasę AppWidgetProvider w pliku AndroidManifest.xml aplikacji, jak 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 widget. Komponent nie musi być eksportowany, chyba że inny proces musi być przesyłany do AppWidgetProvider, co zwykle nie jest konieczne.

Element <intent-filter> musi zawierać element <action> z atrybutem android:name. Ten atrybut określa, że AppWidgetProvider akceptuje ACTION_APPWIDGET_UPDATE transmisję. To jedyna transmisja, którą musisz wyraźnie zadeklarować. AppWidgetManagerautomatycznie wysyła wszystkie inne transmisje widżetu do AppWidgetProvider w razie potrzeby.

Element <meta-data> określa zasób AppWidgetProviderInfo i wymaga podania tych atrybutów:

  • android:name: określa nazwę metadanych. Użyj atrybutu android.appwidget.provider, aby zidentyfikować dane jako opis AppWidgetProviderInfo.
  • android:resource: określa lokalizację zasobu AppWidgetProviderInfo.

Implementacja klasy AppWidgetProvider

Klasa AppWidgetProvider rozszerza klasę BroadcastReceiver jako klasa ułatwiająca obsługę 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ępują te zdarzenia transmisji, są wywoływane te metody:AppWidgetProvider:

onUpdate()
Jest ona wywoływana w celu aktualizowania widżetu w określonych odstępach czasu zdefiniowanych przez atrybut updatePeriodMillis w elementach AppWidgetProviderInfo. Więcej informacji znajdziesz w tabeli z opisem dodatkowych atrybutów widżetów na tej stronie.
Ta metoda jest też wywoływana, gdy użytkownik dodaje widżet, aby wykonać niezbędną konfigurację, np. zdefiniować przetwarzacze zdarzeń dla obiektów View lub uruchomić zadania wczytywania danych do wyświetlenia w widżecie. Jeśli jednak deklarujesz aktywność konfiguracji bez flagi configuration_optional, ta metoda nie zostanie wywołana, gdy użytkownik doda widżet, ale będzie wywoływana podczas kolejnych aktualizacji. Po zakończeniu konfiguracji pierwszą aktualizację musi wykonać aktywność konfiguracji. Więcej informacji znajdziesz w artykule Włączanie możliwości konfigurowania widżetów aplikacji przez użytkowników.
Najważniejsza funkcja zwracana przez tę funkcję to onUpdate(). Więcej informacji znajdziesz na stronie Obsługa zdarzeń za pomocą klasy onUpdate().
onAppWidgetOptionsChanged()

Jest ona wywoływana przy pierwszym umieszczeniu widżetu i za każdym razem, gdy jego rozmiar zostanie zmieniony. Za pomocą tego wywołania zwrotnego możesz wyświetlać lub ukrywać treści na podstawie zakresów rozmiarów widżetu. Aby uzyskać zakresy rozmiarów (a od Androida 12 – listę możliwych rozmiarów, które może przyjąć instancja widżetu), wywołaj funkcję getAppWidgetOptions(), która zwraca obiekt Bundle zawierający:

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 on wywoływany, gdy instancja widżetu jest tworzona po raz pierwszy. Jeśli na przykład użytkownik doda 2 wystąpienia Twojego widżetu, metoda ta zostanie wywołana tylko raz. Jeśli chcesz otworzyć nową bazę danych lub przeprowadzić inną konfigurację, która musi zostać wykonana tylko raz w przypadku wszystkich wystąpień widżetu, możesz to zrobić w tym miejscu.

onDisabled(Context)

Ta metoda jest wywoływana, gdy ostatnia instancja widżetu zostanie usunięta z hosta widżetu. Tutaj możesz uporządkować wszystkie działania wykonane w onEnabled(Context), na przykład usunąć tymczasową bazę danych.

onReceive(Context, Intent)

Jest on wywoływany w przypadku każdej transmisji i przed każdą z poprzednich metod wywołania zwrotnego. Zazwyczaj nie musisz stosować tej metody, ponieważ domyślna implementacja AppWidgetProvider filtruje wszystkie transmisje widżetu i w odpowiednich przypadkach wywołuje poprzednie metody.

Implementację klasy AppWidgetProvider musisz zadeklarować jako odbiornik transmisji za pomocą elementu <receiver> w komponencie AndroidManifest. Więcej informacji znajdziesz na stronie Deklarowanie widżetu w pliku manifestu.

Obsługa zdarzeń za pomocą klasy onUpdate()

Najważniejszym wywołaniem funkcji AppWidgetProvider jest onUpdate(), ponieważ jest ono wywoływane, gdy każdy widżet jest dodawany do hosta, chyba że używasz aktywności konfiguracji bez flagi configuration_optional. Jeśli widżet akceptuje jakiekolwiek zdarzenia interakcji z użytkownikiem, zarejestruj moduły obsługi zdarzeń w tym wywołaniu zwrotnym. Jeśli widżet nie tworzy tymczasowych plików ani baz danych i nie wykonuje innych zadań, które wymagają wyczyszczenia, onUpdate() może być jedyną metodą wywołania, którą musisz zdefiniować.

Jeśli na przykład chcesz utworzyć widżet z przyciskiem, który po kliknięciu uruchamia działanie, możesz użyć takiej implementacji funkcji 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 element AppWidgetProvider definiuje tylko metodę onUpdate(), za pomocą której tworzy element PendingIntent, który uruchamia element Activity, i dołącza go do przycisku widżetu za pomocą elementu setOnClickPendingIntent(int, PendingIntent). Zawiera on pętlę, która przechodzi po każdym wpisie w tablicy appWidgetIds, czyli tablicy identyfikatorów identyfikujących każdy widżet utworzony przez tego dostawcę. Jeśli użytkownik utworzy więcej niż 1 wystąpieni widżetu, wszystkie zostaną zaktualizowane jednocześnie. Jednak dla wszystkich wystąpień widżetu zarządzana jest tylko jedna updatePeriodMillis. Jeśli na przykład harmonogram aktualizacji jest ustawiony co 2 godziny, a po godzinie od dodania pierwszego widgeta dodasz drugi, oba zostaną zaktualizowane zgodnie z harmonogramem pierwszego, a drugi okres aktualizacji zostanie zignorowany. Oba te raporty są aktualizowane co 2 godziny, a nie co godzinę.

Więcej informacji znajdziesz w próbnej klasie ExampleAppWidgetProvider.java.

Odbieranie intencji dotyczących transmisji widżetów

AppWidgetProvider to klasa ułatwiająca. Jeśli chcesz otrzymywać transmisje widgeta bezpośrednio, możesz zaimplementować własne BroadcastReceiver lub zastąpić wywołanie zwrotne onReceive(Context,Intent). Intencje, na które musisz zwrócić uwagę, to:

Tworzenie układu widżetu

Musisz zdefiniować początkowy układ widżetu w formacie XML i zapisać go w katalogu res/layout/ projektu. Szczegółowe informacje znajdziesz w wytycznych dotyczących projektowania.

Jeśli znasz schematy, utworzenie układu widżetu jest proste. Pamiętaj jednak, że układy widżetów są oparte na RemoteViews, który nie obsługuje wszystkich rodzajów układów ani widoków widżetów. Nie możesz używać widoków niestandardowych ani podklas widoków obsługiwanych przez RemoteViews.

RemoteViews obsługuje też ViewStub, czyli niewidoczny, zerowy View, którego można użyć do leniwego napełniania zasobów układu w czasie działania.

Obsługa stanów

Android 12 obsługuje stany za pomocą tych istniejących komponentów:

Widżet nadal nie ma stanu. Aplikacja musi przechowywać stan i rejestrować zdarzenia zmiany stanu.

Przykład widżetu listy zakupów pokazującego stan
Rysunek 3. Przykład zachowania zależnego od stanu.

Przykładowy kod poniżej pokazuje, jak zaimplementować 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 projekty: jeden kierowany na urządzenia z Androidem 12 lub nowszym w folderze res/layout-v31, a drugi na poprzednią wersję Androida 11 lub starszą w domyślnym folderze res/layout.

Zastosowanie zaokrąglonych narożników

Android 12 wprowadza te parametry systemu, które umożliwiają ustawienie zaokrąglonych rogów widżetu:

  • system_app_widget_background_radius: promień narożnika tła widżetu, który nigdy nie przekracza 28 dp.

  • system_app_widget_inner_radius: promień zaokrąglenia rogów dowolnego widoku w widżecie. Jest to dokładnie o 8 dp mniejszy od promienia tła, aby zapewnić prawidłowe wyrównanie przy użyciu marginesu 8 dp.

Ten przykład pokazuje widżet, który używa wartości system_app_widget_background_radius dla rogu widżetu i system_app_widget_inner_radius dla widoków wewnątrz widżetu.

Widżet pokazujący promień tła widżetu i widoki wewnątrz widżetu
Rysunek 4. zaokrąglone rogi.

1 Róg widżetu.

2 Rzut oka na widok wewnątrz widżetu.

Ważne uwagi dotyczące zaokrąglonych rogów

  • Producenci urządzeń i inne niż domyślne programy uruchamiania mogą zastąpić parametr system_app_widget_background_radius wartością mniejszą niż 28 dp. Wartość parametru system_app_widget_inner_radius jest zawsze mniejsza o 8 pikseli od wartości parametru system_app_widget_background_radius.
  • Jeśli widżet nie używa @android:id/background ani nie definiuje tła, które przycina zawartość na podstawie obrysu, a wartość android:clipToOutline jest ustawiona na true, program uruchamiający automatycznie rozpoznaje tło i przycina widżet za pomocą prostokąta o zaokrąglonych rogach o wysokości do 16 dp. Zapoznaj się z artykułem Sprawdzanie zgodności widżetu z Androidem 12.

Aby zapewnić zgodność widżetu z wcześniejszymi wersjami systemu Android, zalecamy zdefiniowanie atrybutów niestandardowych i użycie niestandardowego motywu, aby zastąpić je w Androidzie 12. Przykładowe pliki 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" />