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 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, aby prawidłowo zarządzać orientacją urządzenia i formatem obrazu, unikać podglądu w orientacji poziomej oraz zapobiegać 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ą ViewModel lub 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, aby był zgodny z bieżącą orientacją ekranu. Unikaj założeń opartych na rotation_0 = portrait, co zagwarantuje precyzyjne interakcje użytkownika.

Kompilacja adaptacyjna

Jeśli Twoja aplikacja jest już adaptacyjna i spełnia wymagania poziomu zoptymalizowanego (poziom 2) określone w wskazówkach 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 trybu 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
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ę (z paskami) a 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ć prawidłowe komponenty nawigacyjne i gęstość treści w zależności od bieżącego stanu urządzenia.

Przedstawienie aplikacji na urządzeniach o rozmiarach należących do klas kompaktowej, średniej i rozszerzonej.
Rysunek 2. Klasy rozmiaru okna.

W tym przykładzie biblioteka adaptacyjna Material 3 określa, ile miejsca jest dostępne w aplikacji. Najpierw wywołuje funkcję currentWindowAdaptiveInfo(), a potem używa 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 (optymalizacja adaptacyjna) lub poziomu 1 (adaptacja zróżnicowana) wskazówek dotyczących jakości aplikacji adaptacyjnych zapewnia, że aplikacja będzie wygodna w użyciu 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 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 orientacji poziomej 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 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 współczynnik proporcji 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ącej bazy kodu Camera2, CameraViewfinder biblioteka (zgodna wstecznie z poziomem interfejsu API 21) jest kolejnym nowoczesnym rozwiązaniem. Upraszcza wyświetlanie przekazu z kamery, używając TextureView lub SurfaceView i stosując wszystkie niezbędne przekształcenia (format obrazu, skalowanie 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 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żący obrót 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 trybie 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 trybie wielu okien lub trybie 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 na 3 części 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 uruchamianiu Activity 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 obracaniu urządzenia fizycznego, 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żyj 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łowy i HALF_OPENED, są obsługiwane zarówno w przypadku urządzeń składanych w orientacji pionowej, jak i poziomej. Jednak etui składane na 3 części 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 użytkownika.

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 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 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 stanu złożenia urządzenia – 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 ekranie.

<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ść na wszystkich urządzeniach i wyświetlaczach. 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 adaptacyjnych aplikacji znajdziesz w wytycznych dotyczących jakości adaptacyjnych aplikacji.