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.

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ą 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 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.
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 niedopasowanymi (letterbox) a dopasowanymi.

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.

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ż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:

  • 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. 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 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 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, touchscreenkeyboard.

Zobacz android:configChangesObsł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, fontScale itd.

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ń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.