Obsługa urządzeń składanych na 3 części i składanych w orientacji poziomej

Składany telefon w orientacji poziomej w pozycji zamkniętej i całkowicie otwartej obok składanego telefonu w pozycji zamkniętej i całkowicie otwartej.

Deweloperzy często napotykają wyjątkowe trudności podczas tworzenia aplikacji na urządzenia składane, zwłaszcza na 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 ekranem zewnętrznym a wewnętrznym (założenia oparte na rotation_0 = 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ądów z kamery w celu prawidłowego zarządzania orientacją urządzenia i formatami obrazu, unikania podglądów 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ą funkcji ViewModel lub podobnych rozwiązań 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, aby był zgodny z bieżącą orientacją ekranu. Unikaj założeń opartych na rotation_0 = portrait, aby zapewnić precyzyjne interakcje użytkownika.

Kompilacja adaptacyjna

Jeśli Twoja aplikacja jest już adaptacyjna i spełnia wymagania dotyczące zoptymalizowanego poziomu (poziom 2) określone w wytycznych dotyczących jakości aplikacji adaptacyjnych, 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 nawigacji głównej 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.
Aplikacja w formacie letterbox na otwartym urządzeniu składanym i ta sama aplikacja w trybie pełnoekranowym z układem adaptacyjnym na innym otwartym urządzeniu składanym.
Rysunek 1. Różnica między układami niedopasowującymi się (w formacie letterbox) a układami dopasowującymi się.

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 bieżącego stanu urządzenia.

Ilustracja aplikacji na urządzeniach o rozmiarach odpowiadających klasom kompaktowej, średniej i rozszerzonej wielkości okna.
Rysunek 2. Klasy rozmiaru okna.

W tym przykładzie używamy biblioteki adaptacyjnej Material 3, aby określić, ile miejsca jest dostępne w aplikacji. Najpierw wywołujemy funkcję currentWindowAdaptiveInfo(), a potem używamy odpowiednich układów dla 3 klas rozmiaru okna:

val adaptiveInfo = currentWindowAdaptiveInfo()
val windowSizeClass = adaptiveInfo.windowSizeClass

when {
  windowSizeClass.isWidthAtLeastBreakpoint(WIDTH_DP_EXPANDED_LOWER_BOUND) -> // Expanded
  windowSizeClass.isWidthAtLeastBreakpoint(WIDTH_DP_MEDIUM_LOWER_BOUND) -> // Medium
  else -> // Compact
}

Więcej informacji znajdziesz w artykule Korzystanie z klas rozmiaru okna.

Jakość aplikacji adaptacyjnych

Przestrzeganie poziomu 2 (aplikacja adaptacyjna zoptymalizowana) lub poziomu 1 (aplikacja adaptacyjna zróżnicowana) wytycznych dotyczących jakości aplikacji adaptacyjnych zapewnia, że aplikacja będzie wygodna w użyciu na urządzeniach z potrójnym składanym ekranem, składanych urządzeniach w orientacji poziomej i innych urządzeniach z dużym ekranem. Wytyczne obejmują krytyczne testy na różnych poziomach, które pozwalają przejść od adaptacyjnego do zróżnicowanego środowiska.

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 (zachowania 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 obliczeń proporcji obrazu (w scenariuszach takich jak tryb wielu okien, tryb okien na pulpicie czy podłączone wyświetlacze) jest rozciągnięty, obrócony, przycięty lub wyświetlany bokiem podgląd z kamery.

Niezgodne założenia

Problem ten często występuje na urządzeniach z dużym ekranem i urządzeniach 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 wyświetlacza i proporcje 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 składanych urządzeń 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:

  • PreviewView prawidł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. Upraszcza wyświetlanie obrazu z kamery, używając TextureView lub SurfaceView i stosując 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) oraz 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 proporcje 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 SurfaceView lub TextureView.
  • Aby uniknąć zniekształceń, upewnij się, że format obrazu wyjściowego Surface jest zgodny z formatem podglądu z kamery.
  • Aplikacja aparatu może być uruchomiona w części ekranu w trybie wielu okien lub okien na pulpicie 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 do obsługi aparatu 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ęć lub 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/rozkładanie i 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łóceń u 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, touchscreenkeyboard.

Zobacz android:configChangesObsługa zmian konfiguracji. Więcej informacji o zarządzaniu stanem aplikacji znajdziesz w artykule Zapisywanie stanów interfejsu.

Zmiany konfiguracji gęstości

Zewnętrzny i wewnętrzny ekran urządzeń składanych w formie trifolda i urządzeń składanych w orientacji poziomej mogą mieć różną gęstość pikseli. Dlatego zarządzanie zmianą konfiguracji w przypadku density wymaga szczególnej uwagi. Gdy zmieni się gęstość wyświetlania, Android zwykle ponownie uruchamia aktywność, co może spowodować utratę danych. Aby zapobiec ponownemu uruchamianiu aktywności przez system, zadeklaruj obsługę gęstości w pliku manifestu i programowo zarządzaj zmianą konfiguracji 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, fontScale itd.

Zadeklarowanie gęstości (i innych zmian konfiguracji) zapobiega ponownemu uruchomieniu aktywności przez system i zamiast tego wywołuje onConfigurationChanged().

Implementacja metody 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ć aktualne 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 Orientacja aplikacji ograniczona na telefonach, ale nie na dużych ekranach.

Pozycje i tryby wyświetlania

Tryby i stany urządzeń składanych, takie jak tryb stołowy i HALF_OPENED, są obsługiwane zarówno w przypadku urządzeń składanych w orientacji pionowej, jak i poziomej. Etui składane na 3 części nie obsługują jednak 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 Jetpack WindowManager API, 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 ekranu i tryb podwójnego ekranu 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:

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 powoduje zablokowanie aplikacji w trybie pionowym, gdy jest ona uruchomiona na zewnętrznym wyświetlaczu, oraz w trybie poziomym, gdy jest uruchomiona na wewnętrznym wyświetlaczu.

<activity
  android:name=".MainActivity"
  android:screenOrientation="nosensor">

Gry i zmiana mapowania 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 grać 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ść z różnymi formatami i wyświetlaczami połączonymi. 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 ze zgodnością na platformie, w szczególności w przypadku podglądu z kamery, zastąpieńzmian w interfejsie Androida 16, które mogą zmienić działanie aplikacji.

Więcej informacji o tworzeniu aplikacji adaptacyjnych znajdziesz w wytycznych dotyczących jakości aplikacji adaptacyjnych.