Twórcy aplikacji często napotykają wyjątkowe trudności podczas tworzenia aplikacji na urządzenia składane, zwłaszcza na urządzenia takie jak Samsung Trifold czy oryginalny Pixel Fold, które otwierają się w formacie poziomym (rotation_0 = landscape). Błędy deweloperów obejmują:
- Nieprawidłowe założenia dotyczące orientacji urządzenia
- Pomijane przypadki użycia
- Niepowodzenie ponownego obliczania lub buforowania wartości w przypadku zmian konfiguracji
Problemy związane z urządzeniem to m.in.:
- Niezgodność naturalnej orientacji urządzenia między wyświetlaczem zewnętrznym a wewnętrznym (założenia oparte na rotation_0 = orientacja pionowa), która powoduje nieprawidłowe działanie aplikacji podczas składania i rozkładania urządzenia.
- Obsługa różnych gęstości ekranu i nieprawidłowych zmian konfiguracji gęstości
- Problemy z podglądem z kamery spowodowane zależnością czujnika aparatu od naturalnej orientacji
Aby zapewnić wysoką jakość obsługi na urządzeniach składanych, skup się na tych kluczowych obszarach:
- określać orientację aplikacji na podstawie rzeczywistego obszaru ekranu, który zajmuje aplikacja, a nie fizycznej orientacji urządzenia;
- Aktualizowanie podglądu z kamery w celu prawidłowego zarządzania orientacją urządzenia i formatami obrazu, unikania podglądu w orientacji poziomej oraz zapobiegania rozciąganiu lub przycinaniu obrazów.
- Zachowaj ciągłość działania aplikacji podczas składania i rozkładania urządzenia, zachowując stan za pomocą
ViewModellub podobnych metod albo ręcznie obsługując zmiany gęstości ekranu i orientacji, co zapobiega ponownemu uruchamianiu aplikacji lub utracie stanu. - W przypadku aplikacji korzystających z czujników ruchu dostosuj układ współrzędnych do bieżącej orientacji ekranu i unikaj założeń opartych na rotation_0 = portrait, co gwarantuje precyzyjne interakcje użytkownika.
Kompilacja adaptacyjna
Jeśli Twoja aplikacja jest już adaptacyjna i spełnia wymagania poziomu zoptymalizowanego (poziom 2) opisane w wytycznych dotyczących jakości aplikacji na duże ekrany, powinna dobrze działać na urządzeniach składanych. Zanim sprawdzisz szczegóły dotyczące urządzeń składanych na 3 części i składanych w orientacji poziomej, zapoznaj się z tymi podstawowymi koncepcjami adaptacyjnego programowania na Androida.
Układy adaptacyjne
Interfejs musi obsługiwać nie tylko różne rozmiary ekranu, ale też zmiany proporcji w czasie rzeczywistym, takie jak rozkładanie urządzenia i włączanie trybów wielu okien lub okien na pulpicie. Więcej informacji o tym, jak:
- Projektowanie i wdrażanie układów adaptacyjnych
- Dostosowywanie głównej nawigacji aplikacji do rozmiaru okna
- Dostosowywanie interfejsu aplikacji za pomocą klas rozmiaru okna
- Uprość implementację układów kanonicznych, takich jak lista-szczegóły, za pomocą interfejsów API Jetpack.
Klasy rozmiarów okien
Urządzenia składane, w tym składane w poziomie i składane na 3 części, mogą natychmiast przełączać się między kompaktowym, średnim i rozszerzonym rozmiarem okna. Zrozumienie i wdrożenie tych klas zapewni, że aplikacja będzie wyświetlać odpowiednie komponenty nawigacyjne i gęstość treści w zależności od stanu urządzenia.
W tym przykładzie użyto biblioteki adaptacyjnej Material 3, aby określić, ile miejsca jest dostępne w aplikacji. Najpierw wywołano funkcję currentWindowAdaptiveInfo(), a potem użyto odpowiednich układów dla 3 klas rozmiaru okna:
val adaptiveInfo = currentWindowAdaptiveInfo(supportLargeAndXLargeWidth = true)
val windowSizeClass = adaptiveInfo.windowSizeClass
when {
windowSizeClass.isWidthAtLeastBreakpoint(WIDTH_DP_EXPANDED_LOWER_BOUND) -> // Large
windowSizeClass.isWidthAtLeastBreakpoint(WIDTH_DP_MEDIUM_LOWER_BOUND) -> // Medium
else -> // Compact
}
Więcej informacji znajdziesz w artykule Korzystanie z klas rozmiarów okien.
Jakość aplikacji na dużych ekranach
Przestrzeganie wytycznych dotyczących jakości aplikacji na duże ekrany na poziomie 2 (aplikacje zoptymalizowane pod kątem dużych ekranów) lub 1 (aplikacje dostosowane do dużych ekranów) zapewnia atrakcyjną obsługę aplikacji na urządzeniach z 3-częściowym ekranem, składanych urządzeniach w orientacji poziomej i innych urządzeniach z dużym ekranem. Wytyczne obejmują krytyczne kontrole na różnych poziomach, które pozwalają przejść od gotowości do wyświetlania reklam adaptacyjnych do zróżnicowanych wrażeń użytkownika.
Android 16 lub nowszy
W przypadku aplikacji kierowanych na Androida 16 (API na poziomie 36) i nowsze system ignoruje ograniczenia dotyczące orientacji, możliwości zmiany rozmiaru i formatu obrazu na wyświetlaczach o najmniejszej szerokości >= 600 dp. Aplikacje wypełniają całe okno wyświetlania niezależnie od współczynnika proporcji i preferowanej orientacji użytkownika, a tryb zgodności letterboxing nie jest już używany.
Specjalne uwagi
Urządzenia trifold i składane w poziomie mają unikalne zachowania sprzętowe, które wymagają specjalnego traktowania, zwłaszcza w przypadku czujników, podglądu z kamery i ciągłości konfiguracji (zachowywania stanu podczas składania, rozkładania lub zmiany rozmiaru).
Podgląd z aparatu
Częstym problemem na urządzeniach składanych w orientacji poziomej lub w przypadku obliczania proporcji obrazu (w scenariuszach takich jak widok wielookienny, okna na komputerze lub podłączone wyświetlacze) jest rozciągnięty, obrócony, przycięty lub wyświetlany bokiem podgląd z kamery.
Niezgodne założenia
Ten problem często występuje na urządzeniach z dużym ekranem i składanych, ponieważ aplikacje mogą zakładać stałe relacje między funkcjami aparatu – takimi jak format obrazu i orientacja czujnika – a funkcjami urządzenia – takimi jak orientacja urządzenia i orientacja naturalna.
Nowe formaty podważają to założenie. Na urządzeniu składanym można zmieniać rozmiar i proporcje wyświetlacza bez zmiany orientacji urządzenia. Na przykład rozłożenie urządzenia zmienia współczynnik proporcji, ale jeśli użytkownik nie obróci urządzenia, jego orientacja pozostanie taka sama. Jeśli aplikacja zakłada, że współczynnik proporcji jest powiązany z obrotem urządzenia, może nieprawidłowo obracać lub skalować podgląd z kamery. To samo może się zdarzyć, jeśli aplikacja zakłada, że orientacja czujnika aparatu jest zgodna z orientacją urządzenia w trybie portretowym, co nie zawsze jest prawdą w przypadku urządzeń składanych w trybie poziomym.
Rozwiązanie 1. Jetpack CameraX (najlepsze)
Najprostszym i najbardziej niezawodnym rozwiązaniem jest użycie biblioteki Jetpack CameraX. Element interfejsu PreviewView został zaprojektowany tak, aby automatycznie obsługiwać wszystkie złożone aspekty podglądu:
PreviewViewprawidłowo dostosowuje się do orientacji czujnika, obrotu urządzenia i skalowania.- Zachowuje on proporcje obrazu z kamery, zwykle przez wyśrodkowanie i przycięcie (FILL_CENTER).
- W razie potrzeby możesz ustawić typ skali na
FIT_CENTER, aby wyświetlić podgląd w formacie letterbox.
Więcej informacji znajdziesz w artykule Implementowanie podglądu w dokumentacji CameraX.
Rozwiązanie 2. CameraViewfinder
Jeśli używasz istniejącego kodu Camera2, biblioteka CameraViewfinder (wstecznie zgodna z interfejsem API na poziomie 21) jest kolejnym nowoczesnym rozwiązaniem. Ułatwia wyświetlanie obrazu z kamery, używając elementu TextureView lub SurfaceView, i stosuje wszystkie niezbędne przekształcenia (proporcje, skalę i obrót).
Więcej informacji znajdziesz w poście na blogu Introducing Camera Viewfinder (w języku angielskim) i w przewodniku dla programistów Camera preview (w języku angielskim).
Rozwiązanie 3. Ręczne wdrożenie Camera2
Jeśli nie możesz używać CameraX ani CameraViewfinder, musisz ręcznie obliczyć orientację i format obrazu oraz zadbać o to, aby obliczenia były aktualizowane przy każdej zmianie konfiguracji:
- Pobierz orientację czujnika aparatu (np. 0, 90, 180, 270 stopni) z
CameraCharacteristics. - Pobierz bieżącą orientację ekranu urządzenia (np. 0, 90, 180, 270 stopni).
- Użyj tych 2 wartości, aby określić niezbędne przekształcenia dla
SurfaceViewlubTextureView. - Aby uniknąć zniekształceń, upewnij się, że format obrazu wyjściowego
Surfacejest zgodny z formatem podglądu z kamery. - Aplikacja aparatu może być uruchomiona w części ekranu w trybie wielu okien lub okien na komputerze albo na podłączonym wyświetlaczu. Z tego powodu rozmiar ekranu nie powinien być używany do określania wymiarów wizjera aparatu. Zamiast tego użyj danych okna.
Więcej informacji znajdziesz w przewodniku dla deweloperów Podgląd z kamery i w filmie Aplikacja Aparat na różnych urządzeniach.
Rozwiązanie 4. Wykonywanie podstawowych działań aparatu za pomocą intencji
Jeśli nie potrzebujesz wielu funkcji aparatu, prostym rozwiązaniem jest wykonywanie podstawowych czynności, takich jak robienie zdjęć czy nagrywanie filmów, za pomocą domyślnej aplikacji aparatu na urządzeniu. Nie musisz integrować się z biblioteką aparatu. Zamiast tego użyj intencji.
Więcej informacji znajdziesz w artykule Intencje związane z aparatem.
Konfiguracja i ciągłość
Urządzenia składane zwiększają wszechstronność interfejsu, ale mogą inicjować więcej zmian konfiguracji niż urządzenia nieskładane. Aplikacja musi obsługiwać te zmiany konfiguracji i ich kombinacje, takie jak obracanie urządzenia, składanie i rozkładanie oraz zmiana rozmiaru okna w trybach wielu okien lub pulpitu, przy jednoczesnym zachowaniu lub przywracaniu stanu aplikacji. Na przykład aplikacje muszą zachowywać ciągłość w tych obszarach:
- stan aplikacji bez awarii lub powodowania zakłócających zmian dla użytkowników (np. podczas przełączania ekranów lub przenoszenia aplikacji na drugi plan);
- Pozycja przewijania pól, które można przewijać
- Tekst wpisywany w polach tekstowych i stan klawiatury
- Pozycja odtwarzania multimediów, aby odtwarzanie zostało wznowione w miejscu, w którym zostało przerwane, gdy zainicjowano zmianę konfiguracji.
Często wywoływane zmiany konfiguracji to screenSize, smallestScreenSize, screenLayout, orientation, density, fontScale, touchscreen i keyboard.
Zobacz android:configChanges i Obsługa zmian konfiguracji. Więcej informacji o zarządzaniu stanem aplikacji znajdziesz w artykule Zapisywanie stanów interfejsu.
Zmiany konfiguracji układu
Zewnętrzny i wewnętrzny ekran urządzeń składanych w formie książki i urządzeń składanych w poziomie mogą mieć różną gęstość pikseli. Dlatego zarządzanie zmianą konfiguracji w przypadku density wymaga szczególnej uwagi. Android zwykle ponownie uruchamia aktywność, gdy zmienia się gęstość wyświetlania, co może spowodować utratę danych. Aby zapobiec ponownemu uruchomieniu aktywności przez system, zadeklaruj obsługę gęstości w pliku manifestu i zarządzaj zmianą konfiguracji programowo w aplikacji.
Konfiguracja pliku AndroidManifest.xml
density: deklaruje, że aplikacja będzie obsługiwać zmianę gęstości ekranu.- Inne zmiany konfiguracji: warto też zgłaszać inne często występujące zmiany konfiguracji, np.
screenSize,orientation,keyboardHidden,fontScaleitd.
Zadeklarowanie gęstości (i innych zmian konfiguracji) zapobiega ponownemu uruchomieniu aktywności przez system i zamiast tego wywołuje onConfigurationChanged().
Implementacja onConfigurationChanged()
Gdy nastąpi zmiana gęstości, musisz zaktualizować zasoby (np. ponownie wczytać mapy bitowe lub ponownie obliczyć rozmiary układu) w wywołaniu zwrotnym:
- Sprawdź, czy wartość DPI zmieniła się na
newConfig.densityDpi. - Resetowanie widoków niestandardowych, elementów rysowalnych itp. do nowej gęstości
Elementy zasobów do przetworzenia
- Zasób obrazu: zastąp mapy bitowe i elementy rysowalne zasobami o określonej gęstości lub bezpośrednio dostosuj skalę.
- Jednostka układu (konwersja z dp na px): ponowne obliczanie rozmiaru widoku, marginesu i wypełnienia.
- Czcionka i rozmiar tekstu: ponowne zastosowanie rozmiaru tekstu w jednostkach sp
- Rysowanie niestandardowe
View/Canvas: zaktualizuj wartości pikseli używane do rysowania.Canvas
Określanie orientacji aplikacji
Podczas tworzenia układu adaptacyjnego nigdy nie polegaj na fizycznym obracaniu urządzenia, ponieważ będzie ono ignorowane na urządzeniach z dużym ekranem, a aplikacja w trybie wielu okien może mieć inną orientację niż urządzenie. Zamiast tego używaj Configuration.orientation lub WindowMetrics, aby określić, czy aplikacja jest obecnie w orientacji poziomej czy pionowej na podstawie rozmiaru okna.
Rozwiązanie 1. Użyj Configuration.orientation
Ta właściwość określa orientację, w której aplikacja jest obecnie wyświetlana.
Rozwiązanie 2. Użyj WindowMetrics#getBounds()
Możesz uzyskać bieżące granice wyświetlania aplikacji i sprawdzić jej szerokość oraz wysokość, aby określić orientację.
Jeśli chcesz ograniczyć orientację aplikacji na telefonach (lub zewnętrznych ekranach urządzeń składanych), ale nie na urządzeniach z dużym ekranem, zapoznaj się z artykułem Ograniczanie orientacji aplikacji na telefonach.
Pozycje i tryby wyświetlania
Pozycje i stany urządzeń składanych, takie jak tryb stołu i HALF_OPENED, są obsługiwane zarówno w przypadku urządzeń składanych w orientacji pionowej, jak i poziomej. Jednak etui trifold nie obsługują trybu stołowego i nie można ich używać HALF_OPENED. Urządzenia składane na 3 części mają większy ekran, który po rozłożeniu zapewnia wyjątkowe wrażenia.
Aby wyróżnić aplikację na urządzeniach składanych obsługujących HALF_OPENED, użyj interfejsów API Jetpack WindowManager, takich jak FoldingFeature.
Więcej informacji o pozycjach, stanach i obsłudze podglądu z aparatu na urządzeniach składanych znajdziesz w tych przewodnikach dla deweloperów:
Urządzenia składane zapewniają wyjątkowe wrażenia podczas oglądania. Tryb tylnego wyświetlacza i tryb dwóch ekranów umożliwiają tworzenie specjalnych funkcji wyświetlania na urządzeniach składanych, takich jak podgląd selfie z tylnego aparatu czy jednoczesne, ale różne wyświetlanie na ekranach wewnętrznym i zewnętrznym. Więcej informacji znajdziesz w tych artykułach:
Blokowanie orientacji w naturalnej orientacji czujnika
W bardzo konkretnych przypadkach użycia, zwłaszcza w przypadku aplikacji, które muszą zajmować cały ekran niezależnie od tego, czy urządzenie jest złożone, flaga nosensor umożliwia zablokowanie aplikacji w naturalnej orientacji urządzenia. Na przykład w przypadku Pixela Fold naturalną orientacją urządzenia po złożeniu jest orientacja pionowa, a po rozłożeniu – pozioma. Dodanie flagi nosensor
wymusza zablokowanie aplikacji w trybie pionowym, gdy jest ona uruchomiona na zewnętrznym wyświetlaczu, i w trybie poziomym, gdy jest uruchomiona na wewnętrznym wyświetlaczu.
<activity
android:name=".MainActivity"
android:screenOrientation="nosensor">
Gry i ponowne mapowanie czujników XR
W przypadku gier i aplikacji XR surowe dane z czujników (np. z żyroskopu lub akcelerometru) są podawane w układzie współrzędnych związanym z urządzeniem. Jeśli użytkownik obróci urządzenie, aby zagrać w grę w trybie poziomym, osie czujnika nie obrócą się wraz z ekranem, co spowoduje nieprawidłowe sterowanie w grze.
Aby rozwiązać ten problem, sprawdź bieżącą wartość Display.getRotation() i odpowiednio zmień mapowanie osi:
- Rotacja 0: x=x, y=y
- Obrót o 90°: x=-y, y=x
- Obrót o 180°: x=-x, y=-y
- Obrót o 270°: x=y, y=-x
W przypadku wektorów rotacji (używanych w aplikacjach kompasu lub XR) użyj funkcji SensorManager.remapCoordinateSystem(), aby zmapować kierunek obiektywu aparatu lub górnej części ekranu na nowe osie na podstawie bieżącej rotacji.
Zgodność aplikacji
Aplikacje muszą być zgodne ze wskazówkami dotyczącymi jakości aplikacji, aby zapewnić kompatybilność na wszystkich urządzeniach i wyświetlaczach połączonych. Jeśli aplikacja nie spełnia wytycznych, producenci urządzeń mogą wdrożyć rozwiązania zapewniające zgodność, ale może to pogorszyć komfort użytkowania.
Więcej informacji znajdziesz na liście obejść problemów z kompatybilnością na platformie, zwłaszcza w przypadku podglądu z kamery, zastąpień i zmian w interfejsie Androida 16, które mogą zmienić działanie aplikacji.
Więcej informacji o tworzeniu aplikacji adaptacyjnych znajdziesz w artykule Jakość aplikacji na duże ekrany.