Tworzenie prostego widżetu

Widżety aplikacji to miniaturowe widoki aplikacji, które możesz umieścić w innych aplikacjach, np. na ekranie głównym, i otrzymywać okresowe aktualizacje. W interfejsie użytkownika takie widoki są nazywane widżetami, które można opublikować, korzystając z dostawcy widżetów aplikacji (lub dostawcy widżetów). Komponent aplikacji, który zawiera inne widżety, jest nazywany hostem widżetu aplikacji (lub hostem widżetu). Ilustracja 1 przedstawia widżet z przykładową muzyką:

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

W tym dokumencie opisujemy, jak opublikować widżet, korzystając z jego dostawcy. Szczegółowe informacje o tworzeniu własnych AppWidgetHost do hostowania widżetów aplikacji znajdziesz w artykule Tworzenie hosta widżetów.

Aby dowiedzieć się, jak zaprojektować widżet, zobacz Omówienie widżetów aplikacji.

Komponenty widżetów

Aby utworzyć widżet, potrzebujesz następujących podstawowych komponentów:

AppWidgetProviderInfo obiekt
Opisuje metadane widżetu, takie jak układ widżetu, częstotliwość aktualizacji i klasa AppWidgetProvider. Parametr AppWidgetProviderInfo jest zdefiniowany w pliku XML, zgodnie z opisem w tym dokumencie.
AppWidgetProvider zajęcia
Określa podstawowe metody, które umożliwiają programowy interfejs za pomocą widżetu. Dzięki niemu możesz odbierać komunikaty o aktualizacjach, włączeniu, wyłączeniu lub usunięciu widżetu. Zadeklarujesz AppWidgetProvider w manifestu, a następniewdrożysz go zgodnie z opisem w tym dokumencie.
Wyświetl układ
Określa początkowy układ widżetu. Układ jest zdefiniowany w pliku XML, jak opisano w tym dokumencie.

Rysunek 2 pokazuje, jak te komponenty wpasowują się w ogólny proces przetwarzania widżetów aplikacji.

Proces przetwarzania widżetu aplikacji
Rysunek 2. Proces przetwarzania widżetu aplikacji.

Jeśli widżet wymaga konfiguracji użytkownika, zaimplementuj aktywność związaną z konfiguracją widżetu aplikacji. Ta aktywność pozwala użytkownikom modyfikować ustawienia widżetu, na przykład strefę czasową widżetu zegara.

Zalecamy też wprowadzenie tych ulepszeń: elastyczne układy widżetów, inne ulepszenia, widżety zaawansowane, widżety kolekcji oraz tworzenie hosta widżetów.

Zadeklarowanie pliku XML AppWidgetProviderInfo

Obiekt AppWidgetProviderInfo określa podstawowe cechy widżetu. Zdefiniuj obiekt AppWidgetProviderInfo w pliku zasobów XML za pomocą jednego elementu <appwidget-provider> i zapisz go w folderze res/xml/ projektu.

Widać to w tym przykładzie:

<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 oknie na podstawie siatki komórek o określonej wysokości i szerokości. Większość ekranów głównych zezwala widżetom na przyjmowanie tylko rozmiarów, które są wielokrotnościami komórek siatki – na przykład dwie komórki w poziomie i trzy komórki w pionie.

Atrybuty rozmiaru widżetu pozwalają określić domyślny rozmiar widżetu oraz określić dolne i górne granice jego rozmiaru. W tym kontekście domyślny rozmiar widżetu to jego rozmiar przy pierwszym dodaniu do ekranu głównego.

W tabeli poniżej opisujemy atrybuty <appwidget-provider> odnoszące się do rozmiarów widżetów:

Atrybuty i opis
targetCellWidth i targetCellHeight (Android 12), minWidth i minHeight
  • Od Androida 12 atrybuty targetCellWidth i targetCellHeight określają domyślny rozmiar widżetu w postaci komórek siatki. Te atrybuty ignorowane w Androidzie 11 i starszych wersjach. Możesz je zignorować, jeśli ekran główny nie obsługuje układu opartego na siatce.
  • Atrybuty minWidth i minHeight określają domyślny rozmiar widżetu w dp. Jeśli wartości minimalnej szerokości lub wysokości widżetu nie są zgodne z wymiarami komórek, są one zaokrąglane w górę do najbliższego rozmiaru komórki.
Zalecamy określenie obu zestawów atrybutów – targetCellWidth i targetCellHeight oraz minWidth i minHeight – aby aplikacja mogła ponownie używać minWidth i minHeight, jeśli urządzenie użytkownika nie obsługuje targetCellWidth i targetCellHeight. Jeśli atrybuty targetCellWidth i targetCellHeight są obsługiwane, mają pierwszeństwo przed atrybutami minWidth i minHeight.
minResizeWidth i minResizeHeight Określ bezwzględny minimalny rozmiar widżetu. Wartości te określają rozmiar, poniżej którego widżet jest nieczytelny lub z innego powodu bezużyteczny. Dzięki tym atrybutom użytkownik może zmienić rozmiar widżetu na mniejszy niż domyślny. Atrybut minResizeWidth jest ignorowany, jeśli ma wartość większą niż minWidth lub jeśli zmienianie rozmiaru w poziomie nie jest włączone. Zobacz resizeMode. Podobnie atrybut minResizeHeight jest ignorowany, jeśli ma wartość większą niż minHeight lub jeśli zmienianie rozmiaru w pionie jest wyłączone.
maxResizeWidth i maxResizeHeight Określ zalecany maksymalny rozmiar widżetu. Jeśli wartości nie są wielokrotnością wymiarów komórki z siatką, 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 zmienianie rozmiaru w poziomie nie jest włączone. Zobacz resizeMode. Podobnie atrybut maxResizeHeight jest ignorowany, jeśli ma wartość większą niż minHeight lub jeśli zmienianie rozmiaru w pionie jest wyłączone. 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 zmieniać rozmiar widżetów ekranu głównego w poziomie, w pionie lub na obu osiach. Użytkownicy naciśnij i przytrzymaj widżet, aby wyświetlić uchwyty zmiany rozmiaru, a następnie przeciągnij uchwyty poziome lub pionowe, aby zmienić jego rozmiar na siatce układu. Wartości atrybutu resizeMode to horizontal, vertical i none. Aby zadeklarować widżet z możliwością zmiany rozmiaru w poziomie i w pionie, użyj właściwości horizontal|vertical.

Przykład

Aby pokazać, jak atrybuty z poprzedniej tabeli wpływają na rozmiar widżetu, załóżmy, że:

  • Komórka siatki ma szerokość 30 dp i wysokość 50 dp.
  • Podana specyfikacja atrybutów:
<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 2 x 2. Rozmiar widżetu można zmniejszyć do 2 x 1 lub maksymalnie 4 x 3.

Android 11 i starsze wersje:

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

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

Wysokość domyślna = Math.ceil(80 / 50) = 2

Domyślny rozmiar widżetu to 3 x 2. Widżet można zmniejszyć do rozmiaru 2 x 1 lub do pełnego ekranu.

Dodatkowe atrybuty widżetu

W tej tabeli opisano atrybuty <appwidget-provider> odnoszące się do jakości innych niż rozmiary widżetów.

Atrybuty i opis
updatePeriodMillis Określa, jak często platforma widżetów żąda aktualizacji z poziomu AppWidgetProvider przez wywoływanie metody wywołania zwrotnego onUpdate(). Nie ma gwarancji, że rzeczywista aktualizacja nastąpi dokładnie w odpowiednim czasie. Zalecamy przeprowadzanie aktualizacji jak najszybciej – nie częściej niż raz na godzinę – w celu oszczędzania baterii. Pełną listę uwag na temat wyboru odpowiedniego okresu aktualizacji znajdziesz w artykule Optymalizacje pod kątem aktualizowania zawartości widżetu.
initialLayout Wskazuje zasób układu, który definiuje układ widżetu.
configure Definiuje działanie, które jest uruchamiane, gdy użytkownik doda widżet, umożliwiając mu konfigurowanie właściwości widżetu. Przeczytaj artykuł Umożliwianie użytkownikom konfigurowania widżetów. Od Androida 12 aplikacja może pomijać początkową konfigurację. Więcej informacji znajdziesz w sekcji Używanie domyślnej konfiguracji widżetu.
description Określa opis, który będzie wyświetlany w selektorze widżetów. 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 udostępniasz w postaci układu XML z domyślnym rozmiarem widżetu. Najlepiej, aby kod XML układu określony jako ten atrybut to taki sam układ XML jak rzeczywisty widżet z realistycznymi wartościami domyślnymi.
  • W Androidzie 11 i starszych wersjach atrybut previewImage określa podgląd tego widżetu po jego skonfigurowaniu i widoczny dla użytkownika podczas wybierania widżetu aplikacji. Jeśli nie zostanie podana, użytkownik będzie mógł zobaczyć ikonę launchera aplikacji. To pole odpowiada atrybutowi android:previewImage elementu <receiver> w pliku AndroidManifest.xml.
Uwaga: zalecamy określenie zarówno atrybutów previewImage, jak i previewLayout, aby aplikacja mogła ponownie używać previewImage, jeśli urządzenie użytkownika nie obsługuje previewLayout. Więcej informacji znajdziesz w artykule o zgodności wstecznej ze skalowalnymi podglądami widżetów.
autoAdvanceViewId Określa identyfikator widoku podrzędnego widżetu, który jest automatycznie zaawansowany 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 lub nowszego prawidłowa jest 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 doda go użytkownik, określ zarówno flagi configuration_optional, jak i reconfigurable. Pomija uruchamianie aktywności konfiguracyjnej po dodaniu widżetu przez użytkownika. Użytkownik może później ponownie skonfigurować widżet.

Użyj klasy AppWidgetProvider do obsługi komunikatów 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 opisano, jak zadeklarować AppWidgetProvider w pliku manifestu, a potem go wdrożyć.

Zadeklarowanie widżetu 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 widżet. Komponentu nie można eksportować, chyba że do rozgłaszania AppWidgetProvider trzeba przesłać oddzielny proces, co zwykle nie jest konieczne.

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

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

  • android:name: określa nazwę metadanych. Używaj parametru android.appwidget.provider, aby wskazać dane jako deskryptor AppWidgetProviderInfo.
  • android:resource: określa lokalizację zasobu AppWidgetProviderInfo.

Implementowanie klasy AppWidgetProvider

Klasa AppWidgetProvider rozszerza BroadcastReceiver jako klasę wygodną do obsługi komunikatów widżetów. Odbiera tylko transmisje zdarzeń odpowiednie dla widżetu, na przykład informacje o tym, kiedy widżet został zaktualizowany, usunięty, włączony i wyłączony. W przypadku wystąpienia takich transmisji wywoływane są następujące metody AppWidgetProvider:

onUpdate()
Wywołuje się to do aktualizowania widżetu w odstępach czasowych określonych przez atrybut updatePeriodMillis w AppWidgetProviderInfo. Więcej informacji znajdziesz w tabeli z opisem dodatkowych atrybutów widżetów na tej stronie.
Metoda ta jest również wywoływana, gdy użytkownik dodaje widżet, dzięki czemu wykonuje podstawową konfigurację, np. definiuje moduły obsługi zdarzeń dla obiektów View lub rozpoczyna zadania wczytywania danych, które mają być wyświetlane w widżecie. Jeśli jednak zadeklarujesz działanie związane z konfiguracją bez flagi configuration_optional, ta metoda nie będzie wywoływana, gdy użytkownik doda widżet, ale jest wywoływana przy kolejnych aktualizacjach. To działanie związane z konfiguracją odpowiada za wykonanie pierwszej aktualizacji po zakończeniu konfiguracji. Więcej informacji znajdziesz w artykule Umożliwianie użytkownikom konfigurowania widżetów aplikacji.
Najważniejsze wywołanie zwrotne to onUpdate(). Więcej informacji znajdziesz w sekcji Obsługiwanie zdarzeń za pomocą klasy onUpdate() na tej stronie.
onAppWidgetOptionsChanged()

Ta funkcja jest wywoływana przy pierwszym umieszczaniu widżetu i przy każdorazowej zmianie jego rozmiaru. Za pomocą tego wywołania zwrotnego możesz wyświetlać lub ukrywać treść na podstawie zakresów rozmiarów widżetu. Aby pobrać zakresy rozmiarów – a od Androida 12 – listę możliwych rozmiarów instancji widżetu – wywołaj metodę getAppWidgetOptions(), która zwraca Bundle o następującej wartości:

onDeleted(Context, int[])

Ta funkcja jest wywoływana za każdym razem, gdy widżet jest usuwany z hosta widżetu.

onEnabled(Context)

Ta funkcja jest wywoływana, gdy wystąpienie widżetu jest tworzone po raz pierwszy. Jeśli na przykład użytkownik doda 2 wystąpienia widżetu, jest to wywoływane tylko za pierwszym razem. Jest to dobre rozwiązanie, jeśli chcesz otworzyć nową bazę danych lub wykonać inną konfigurację, która wystarczy przeprowadzić dla wszystkich instancji widżetu tylko raz.

onDisabled(Context)

Jest ona wywoływana, gdy ostatnie wystąpienie widżetu zostanie usunięte z hosta widżetu. W tym miejscu usuniesz całą pracę wykonaną w onEnabled(Context), na przykład usunięcie tymczasowej bazy danych.

onReceive(Context, Intent)

Jest ono wywoływane w przypadku każdej transmisji i przed każdą z poprzedzających ją metod wywołania zwrotnego. Zwykle nie musisz implementować tej metody, ponieważ domyślna implementacja AppWidgetProvider filtruje wszystkie komunikaty widżetów i wywołuje poprzednie metody odpowiednio.

Musisz zadeklarować implementację klasy AppWidgetProvider jako odbiornik za pomocą elementu <receiver> w AndroidManifest. Więcej informacji znajdziesz w sekcji Deklarowanie widżetu w pliku manifestu na tej stronie.

Obsługuj zdarzenia za pomocą klasy onUpdate()

Najważniejsze wywołanie zwrotne AppWidgetProvider to onUpdate(), ponieważ jest ono wywoływane przy dodawaniu każdego widżetu do hosta, chyba że użyjesz działania konfiguracyjnego bez flagi configuration_optional. Jeśli widżet akceptuje zdarzenia interakcji użytkownika, zarejestruj moduły obsługi zdarzeń w tym wywołaniu zwrotnym. Jeśli widżet nie tworzy plików tymczasowych ani baz danych albo nie wykonuje innych zadań, które wymagają wyczyszczenia, jedyną metodą wywołania zwrotnego, jaką musisz zdefiniować, może być onUpdate().

Jeśli np. chcesz mieć widżet z przyciskiem, który po kliknięciu uruchamia aktywność po kliknięciu, 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(), wykorzystując ją do utworzenia PendingIntent, która uruchamia Activity i dołącza ją do przycisku widżetu za pomocą setOnClickPendingIntent(int, PendingIntent). Zawiera pętlę, która powoduje iterację każdego wpisu w usłudze appWidgetIds, czyli tablicę identyfikatorów identyfikujących każdy widżet utworzony przez tego dostawcę. Jeśli użytkownik utworzy więcej niż jedno wystąpienie widżetu, wszystkie zostaną zaktualizowane jednocześnie. Dla wszystkich instancji widżetu zarządzany jest jednak tylko 1 harmonogram updatePeriodMillis. Jeśli np. harmonogram aktualizacji jest zdefiniowany na 2 godziny, a godzinę po dodaniu widżetu z drugim wystąpieniem, zostaną one zaktualizowane w okresie zdefiniowanym przez pierwszy, a drugi okres aktualizacji zostanie zignorowany. Aktualizują się co 2 godziny, a nie co godzinę.

Więcej informacji znajdziesz w przykładowej klasie ExampleAppWidgetProvider.java.

Odbieranie intencji transmisji widżetu

AppWidgetProvider to zajęcia wygodne. Jeśli chcesz bezpośrednio otrzymywać komunikaty z widżetu, możesz zaimplementować własny element BroadcastReceiver lub zastąpić wywołanie zwrotne onReceive(Context,Intent). Oto intencje, na których musisz się skupić:

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 narzędziu RemoteViews, który nie obsługuje wszystkich rodzajów układów lub widżetów. Nie możesz używać niestandardowych widoków ani podklas widoków obsługiwanych przez RemoteViews.

RemoteViews obsługuje również ViewStub, czyli niewidoczny element View o zerowym rozmiarze, którego można używać do leniwego zwiększania zasobów układu w czasie działania.

Obsługa zachowania stanowego

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

Widżet pozostaje bezstanowy. Aplikacja musi przechowywać stan i rejestrować zdarzenia zmiany stanu.

Przykładowy widżet listy zakupów pokazujący zachowanie stanowe
Rysunek 3. Przykład zachowania stanowego.

Poniższy przykładowy kod 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));

Udostępnij 2 układy: jeden jest kierowany na urządzenia z Androidem 12 lub nowszym (res/layout-v31), a drugi w domyślnym folderze res/layout.

Stosuj zaokrąglone rogi.

Android 12 wprowadza te parametry systemowe pozwalające ustawić promienie zaokrąglonych rogów widżetu:

Poniższy przykład przedstawia widżet, który używa system_app_widget_background_radius jako rogu widżetu i system_app_widget_inner_radius w przypadku widoków wewnątrz widżetu.

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

1 Róg widżetu.

2 Róg widoku w widżecie.

Ważne informacje o zaokrąglonych rogach

  • Programy uruchamiające i producenci innych urządzeń mogą zastąpić parametr system_app_widget_background_radius mniejszy niż 28 dp. Parametr system_app_widget_inner_radius jest zawsze o 8 dp mniejszy niż wartość system_app_widget_background_radius.
  • Jeśli widżet nie używa @android:id/background lub ma zdefiniowany tło, które nakłada treść na podstawie obrysu (android:clipToOutline ma wartość true), program uruchamiający automatycznie rozpoznaje tło i przycina widżet za pomocą prostokąta z zaokrąglonymi rogami do 16 dp. Zapoznaj się z sekcją Sprawdzanie, czy widżet jest zgodny z Androidem 12.

Aby zapewnić zgodność widżetów z poprzednimi wersjami Androida, zalecamy zdefiniowanie atrybutów niestandardowych i zastąpienie ich motywem niestandardowym, jak widać 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" />