Na tej stronie opisujemy ulepszenia w zakresie rozmiaru widżetów i zwiększające jej elastyczność wprowadzone w Androidzie 12 (poziom interfejsu API 31). Wyjaśniamy też, jak określić rozmiar widżetu.
Używanie ulepszonych interfejsów API do rozmiarów i układów widżetów
Począwszy od Androida 12 (poziom interfejsu API 31) możesz dodawać bardziej precyzyjne atrybuty rozmiaru i elastyczne układy, wykonując te czynności w sposób opisany w poniższych sekcjach:
stosowanie układów elastycznych lub ścisłych układów;
W poprzednich wersjach Androida można było ustalić zakresy rozmiarów widżetu, korzystając z elementów OPTION_APPWIDGET_MIN_WIDTH
, OPTION_APPWIDGET_MIN_HEIGHT
, OPTION_APPWIDGET_MAX_WIDTH
i OPTION_APPWIDGET_MAX_HEIGHT
, a następnie oszacować rozmiar widżetu, ale ta metoda nie działa w niektórych sytuacjach. W przypadku widżetów kierowanych na Androida 12 lub nowszego zalecamy stosowanie elastycznych lub ścisłych układów.
Określanie dodatkowych ograniczeń rozmiaru widżetów
W Androidzie 12 dodajemy interfejsy API, dzięki którym rozmiar widżetu działa w stabilny sposób na różnych urządzeniach o różnych rozmiarach ekranów.
Oprócz dotychczasowych atrybutów minWidth
, minHeight
, minResizeWidth
i minResizeHeight
użyj też tych nowych atrybutów appwidget-provider
:
targetCellWidth
itargetCellHeight
: określ docelowy rozmiar widżetu na podstawie komórek siatki programu uruchamiającego. Jeśli określisz atrybuty, będą one używane zamiastminWidth
lubminHeight
.maxResizeWidth
imaxResizeHeight
: określ maksymalny rozmiar, do którego program uruchamiający pozwala użytkownikowi zmienić rozmiar widżetu.
Poniższy kod XML pokazuje, jak używać atrybutów rozmiaru.
<appwidget-provider
...
android:targetCellWidth="3"
android:targetCellHeight="2"
android:maxResizeWidth="250dp"
android:maxResizeHeight="110dp">
</appwidget-provider>
Dodaj układy elastyczne
Jeśli układ musi się zmieniać w zależności od rozmiaru widżetu, zalecamy utworzenie małego zestawu układów o różnych rozmiarach. Jeśli nie jest to możliwe, możesz też podać układy na podstawie dokładnego rozmiaru widżetu w czasie działania, jak opisano na tej stronie.
Ta funkcja zapewnia płynniejsze skalowanie i ogólnie poprawia kondycję systemu, ponieważ system nie musi wybudzać aplikacji za każdym razem, gdy wyświetla widżet w innym rozmiarze.
Poniższy przykładowy kod pokazuje, jak wyświetlić listę układów.
Kotlin
override fun onUpdate(...) { val smallView = ... val tallView = ... val wideView = ... 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) }
Java
@Override public void onUpdate(...) { RemoteViews smallView = ...; RemoteViews tallView = ...; RemoteViews wideView = ...; Map<SizeF, RemoteViews> viewMapping = new ArrayMap<>(); viewMapping.put(new SizeF(150f, 100f), smallView); viewMapping.put(new SizeF(150f, 200f), tallView); viewMapping.put(new SizeF(215f, 100f), wideView); RemoteViews remoteViews = new RemoteViews(viewMapping); appWidgetManager.updateAppWidget(id, remoteViews); }
Załóżmy, że widżet ma te atrybuty:
<appwidget-provider
android:minResizeWidth="160dp"
android:minResizeHeight="110dp"
android:maxResizeWidth="250dp"
android:maxResizeHeight="200dp">
</appwidget-provider>
Poprzedni fragment kodu:
smallView
obsługuje rozdzielczość od 160 dp (minResizeWidth
) × 110 dp (minResizeHeight
) do 160 dp × 199 dp (następny punkt odcięcia – 1 dp).tallView
obsługuje rozdzielczość od 160 dp × 200 do 214 dp (następny punkt odcięcia – 1) × 200 dp.wideView
obsługuje rozdzielczość od 215 dp × 110 dp (minResizeHeight
) do 250 dp (maxResizeWidth
) × 200 dp (maxResizeHeight
).
Widżet musi obsługiwać zakres rozmiarów od minResizeWidth
× minResizeHeight
do maxResizeWidth
× maxResizeHeight
. W tym zakresie możesz określić punkt odcięcia, aby zmienić układ.
Podaj dokładne układy
Jeśli mały zestaw układów elastycznych nie jest dostępny, możesz zastosować różne układy dostosowane do rozmiarów, w których wyświetla się widżet. Zwykle są to 2 rozmiary dla telefonów (orientacja pionowa i pozioma) oraz 4 rozmiary dla urządzeń składanych.
Aby wdrożyć to rozwiązanie, aplikacja musi wykonać te czynności:
Przeciążenie
AppWidgetProvider.onAppWidgetOptionsChanged()
, które jest wywoływane po zmianie zbioru rozmiarów.Wywołanie funkcji
AppWidgetManager.getAppWidgetOptions()
, która zwraca wartośćBundle
zawierającą rozmiary.Uzyskaj dostęp do klucza
AppWidgetManager.OPTION_APPWIDGET_SIZES
zBundle
.
Poniższy przykładowy kod pokazuje, jak określić dokładne układy.
Kotlin
override fun onAppWidgetOptionsChanged( context: Context, appWidgetManager: AppWidgetManager, id: Int, newOptions: Bundle? ) { super.onAppWidgetOptionsChanged(context, appWidgetManager, id, newOptions) // Get the new sizes. val sizes = newOptions?.getParcelableArrayList<SizeF>( AppWidgetManager.OPTION_APPWIDGET_SIZES ) // 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 { }
Java
@Override public void onAppWidgetOptionsChanged( Context context, AppWidgetManager appWidgetManager, int appWidgetId, Bundle newOptions) { super.onAppWidgetOptionsChanged(context, appWidgetManager, appWidgetId, newOptions); // Get the new sizes. ArrayList<SizeF> sizes = newOptions.getParcelableArrayList(AppWidgetManager.OPTION_APPWIDGET_SIZES); // Check that the list of sizes is provided by the launcher. if (sizes == null || sizes.isEmpty()) { return; } // Map the sizes to the RemoteViews that you want. Map<SizeF, RemoteViews> viewMapping = new ArrayMap<>(); for (SizeF size : sizes) { viewMapping.put(size, createRemoteViews(size)); } RemoteViews remoteViews = new RemoteViews(viewMapping); appWidgetManager.updateAppWidget(id, remoteViews); } // Create the RemoteViews for the given size. private RemoteViews createRemoteViews(SizeF size) { }
Określanie rozmiaru widżetu
Każdy widżet musi definiować targetCellWidth
i targetCellHeight
w przypadku urządzeń z Androidem 12 lub nowszym albo minWidth
i minHeight
w przypadku wszystkich wersji Androida, które domyślnie wskazują minimalną ilość miejsca zajmowanego przez urządzenie. Jednak gdy użytkownicy dodają widżet do ekranu głównego, zajmuje on zwykle więcej niż określona przez Ciebie minimalna szerokość i wysokość.
Ekrany główne Androida to siatka dostępnych miejsc, w których mogą umieszczać widżety i ikony. Ta siatka może się różnić w zależności od urządzenia, np. w wielu słuchawkach jest w siatce 5 x 4, a tablety – większą. Po dodaniu widżetu zostaje on rozciągnięty tak, aby zajmował minimalną liczbę komórek w poziomie i w pionie wymaganą do spełnienia ograniczeń dotyczących targetCellWidth
i targetCellHeight
na urządzeniach z Androidem 12 lub nowszym albo minWidth
i minHeight
na urządzeniach z Androidem 11 (poziom interfejsu API 30) lub niższym.
Szerokość i wysokość komórki oraz rozmiar automatycznych marginesów stosowanych do widżetów mogą się różnić w zależności od urządzenia. W tabeli poniżej znajdziesz oszacowanie minimalnych wymiarów widżetu w typowej słuchawce z siatką o wymiarach 5 × 4, z uwzględnieniem liczby żądanych komórek siatki:
Liczba komórek (szerokość x wysokość) | Rozmiar dostępny w trybie pionowym (dp) | Rozmiar dostępny w trybie poziomym (dp) |
---|---|---|
1x1 | 57x102dp | 127x51dp |
2 × 1 | 130x102dp | 269x51dp |
3x1 | 203x102dp | 412x51dp |
10 × 15 cm | 276x102dp | 554x51dp |
5 × 1 | 349x102dp | 697x51dp |
5 × 2 | 349x220dp | 697x117dp |
13 × 15 cm | 349x337dp | 697x184dp |
13 × 15 cm | 349x455dp | 697x250dp |
… | ... | … |
n x m | (73 n – 16) x (118 m – 16) | (142 n – 15) x (66 m – 15) |
Używaj rozmiarów komórek w trybie portretowym, aby przekazywać wartości atrybutów minWidth
, minResizeWidth
i maxResizeWidth
. Podobnie używaj rozmiarów komórek w trybie poziomym, aby podać wartości atrybutów minHeight
, minResizeHeight
i maxResizeHeight
.
Powodem jest to, że w orientacji pionowej szerokość komórki jest zwykle mniejsza niż w trybie poziomym, a wysokość komórki jest zwykle mniejsza w trybie poziomym niż pionowym.
Jeśli na przykład chcesz, aby na urządzeniu Google Pixel 4 szerokość widżetu można było zmienić w dół do jednej komórki, ustaw minResizeWidth
na nie większą niż 56 dp. Dzięki temu wartość atrybutu minResizeWidth
będzie mniejsza niż 57 dp, bo komórka ma co najmniej 57 dp szerokości w orientacji pionowej.
I podobnie, jeśli chcesz, aby wysokość widżetu można było zmienić w jednej komórce na tym samym urządzeniu, ustaw minResizeHeight
na maksymalnie 50 dp. Dzięki temu wartość atrybutu minResizeHeight
będzie mniejsza niż 51 dp, bo jedna komórka ma co najmniej 51 dp w trybie poziomym.
Rozmiar każdego widżetu można zmieniać w zakresie rozmiarów od atrybutów minResizeWidth
/minResizeHeight
do maxResizeWidth
/maxResizeHeight
, co oznacza, że musi się dostosować do dowolnych zakresów rozmiarów między nimi.
Aby na przykład ustawić domyślny rozmiar widżetu w miejscu docelowym, możesz użyć tych atrybutów:
<appwidget-provider
android:targetCellWidth="3"
android:targetCellHeight="2"
android:minWidth="180dp"
android:minHeight="110dp">
</appwidget-provider>
Oznacza to, że domyślny rozmiar widżetu to 3 x 2 komórki określone za pomocą atrybutów targetCellWidth
i targetCellHeight
– lub 180 × 110 dp w przypadku urządzeń z Androidem 11 lub starszym, zgodnie z zasadami minWidth
i minHeight
. W tym drugim przypadku rozmiar komórek
może się różnić w zależności od urządzenia.
Aby ustawić obsługiwane zakresy rozmiarów widżetu, możesz ustawić te atrybuty:
<appwidget-provider
android:minResizeWidth="180dp"
android:minResizeHeight="110dp"
android:maxResizeWidth="530dp"
android:maxResizeHeight="450dp">
</appwidget-provider>
Jak określono w poprzednich atrybutach, szerokość widżetu można zmienić w zakresie od 180 dp do 530 dp, a jego wysokość można zmieniać z zakresu od 110 dp do 450 dp. Następnie można zmieniać rozmiar widżetu z 3 x 2 na 5 x 2, pod warunkiem że spełnione są te warunki:
- Urządzenie ma siatkę 5 x 4.
- Mapowanie między liczbą komórek a rozmiarem dostępnym w dps jest zgodne z tabelą przedstawiającą oszacowanie minimalnych wymiarów na tej stronie.
- Widżet dostosowuje się do wybranego zakresu rozmiarów.
Kotlin
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))
Java
RemoteViews smallView = new RemoteViews(context.getPackageName(), R.layout.widget_weather_forecast_small); RemoteViews mediumView = new RemoteViews(context.getPackageName(), R.layout.widget_weather_forecast_medium); RemoteViews largeView = new RemoteViews(context.getPackageName(), R.layout.widget_weather_forecast_large); Map<SizeF, RemoteViews> viewMapping = new ArrayMap<>(); viewMapping.put(new SizeF(180f, 110f), smallView); viewMapping.put(new SizeF(270f, 110f), mediumView); viewMapping.put(new SizeF(270f, 280f), largeView); RemoteViews remoteViews = new RemoteViews(viewMapping); appWidgetManager.updateAppWidget(id, remoteViews);
Załóżmy, że widżet używa układów elastycznych zdefiniowanych we wcześniejszych fragmentach kodu. Oznacza to, że układ określony jako R.layout.widget_weather_forecast_small
jest używany od 180 dp (minResizeWidth
) x 110 dp (minResizeHeight
) do 269 x 279 dp (następne punkty odcięcia – 1). Podobnie parametr R.layout.widget_weather_forecast_medium
jest używany w zakresie od 270 x 110 dp do 270 x 279 dp, a R.layout.widget_weather_forecast_large
jest używany w zakresie od 270 x 280 dp do 530 dp (maxResizeWidth
) x 450 dp (maxResizeHeight
).
Gdy użytkownik zmieni rozmiar widżetu, jego wygląd będzie się zmieniał w zależności od rozmiaru w komórkach, jak pokazano w poniższych przykładach.