W tym artykule omawiamy, jak skonfigurować w aplikacji przypadki użycia Aparatu X, aby uzyskać
z poprawnymi informacjami o obróceniu, niezależnie od tego,
ImageAnalysis
lub ImageCapture
. A więc:
- Element
Analyzer
przypadku użyciaImageAnalysis
powinien otrzymywać ramki z atrybutem właściwy obrót. - W przypadku użycia funkcji
ImageCapture
zdjęcia powinny być wykonywane z prawidłowym obrotem.
Terminologia
W tym temacie posługujemy się poniższą terminologią, dlatego warto zrozumieć, co oznaczają poszczególne terminy jest ważne.
- Orientacja wyświetlacza
- Wskazuje, która strona urządzenia jest u góry. Można ją ustawić jedną z czterech wartości: orientacja pionowa, orientacja pozioma, orientacja pionowa lub odwrotna; w orientacji poziomej.
- Obrót wyświetlacza
- To wartość zwracana przez funkcję
Display.getRotation()
oraz przedstawia stopień obrotu urządzenia w lewo i jej naturalnej orientacji. - Rotacja docelowa
- To jest liczba stopni, o którą ma się obrócić aby osiągnąć naturalną orientację.
Określanie rotacji docelowej
W przykładach poniżej pokazujemy, jak określić docelową rotację urządzenia. na podstawie jej naturalnej orientacji.
Przykład 1. Naturalna orientacja pionowa
Przykład urządzenia: Pixel 3 XL | |
---|---|
Naturalna orientacja = Orientacja pionowa Obrót wyświetlacza = 0 |
|
Naturalna orientacja = Orientacja pionowa Obrót wyświetlacza = 90 |
Przykład 2. Naturalna orientacja pozioma
Przykład urządzenia: Pixel C | |
---|---|
Orientacja naturalna = Pozioma Obrót wyświetlacza = 0 |
|
Orientacja naturalna = Pozioma Obrót wyświetlacza = 270 |
Obrót obrazu
Co jest gotowe? Orientacja czujnika jest zdefiniowana w Androidzie jako stała reprezentująca stopnie (0, 90, 180, 270), od którego obraca się czujnik U góry urządzenia, gdy jest ono w naturalnym położeniu. Dla wszystkich przypadków na diagramach obrót obrazu określa, w jaki sposób dane powinny być obrócono w prawo, aby wyświetlić widok pionowo.
W przykładach poniżej pokazujemy, jak powinien być obrócony obraz w zależności od orientacji czujnika aparatu. Zakładają też, że rotacja docelowa jest ustawiona na obrót wyświetlacza.
Przykład 1: czujnik obrócony o 90 stopni
Przykład urządzenia: Pixel 3 XL | |
---|---|
Obrót wyświetlacza = 0 |
|
Obrót wyświetlacza = 90 |
Przykład 2: czujnik obrócony o 270 stopni
Przykład urządzenia: Nexus 5X | |
---|---|
Obrót wyświetlacza = 0 |
|
Obrót wyświetlacza = 90 |
Przykład 3: czujnik obrócony o 0 stopni
Przykład urządzenia: Pixel C (tablet) | |
---|---|
Obrót wyświetlacza = 0 |
|
Obrót wyświetlacza = 270 |
Obliczanie obrotu obrazu
Analiza obrazu
Urządzenie Analyzer
, z którego korzysta ImageAnalysis
, odbiera z kamery obrazy w postaci:
ImageProxy
s Każdy obraz zawiera informacje o rotacji, które są dostępne
przez:
val rotation = imageProxy.imageInfo.rotationDegrees
Ta wartość określa kąt, o jaki obraz musi zostać obrócony
w prawo, aby dopasować się do obrotu docelowego elementu ImageAnalysis
. W kontekście
aplikacji na Androida, rotacja docelowa w grupie ImageAnalysis
zwykle odpowiada
do orientacji ekranu.
Robienie zdjęć
Do instancji ImageCapture
dołączone jest wywołanie zwrotne, które informuje o przechwyceniu
wynik jest gotowy. Efektem może być zrzut ekranu lub błąd.
Podczas robienia zdjęcia możesz uzyskać oddzwanianie z jednego z tych numerów: typy:
OnImageCapturedCallback
: odbiera obraz z dostępem w pamięci w ma postaćImageProxy
.OnImageSavedCallback
: wywoływane po wykonaniu przechwyconego obrazu. zapisane w lokalizacji określonej przezImageCapture.OutputFileOptions
Dostępne opcje toFile
,OutputStream
lub lokalizację w:MediaStore
.
Obrót zrobionego obrazu niezależnie od jego formatu (ImageProxy
,
File
, OutputStream
, MediaStore Uri
) pokazuje stopnie obrotu według
które należy obrócić w prawo, aby dopasowaćImageCapture
kierowania reklam, czyli w kontekście aplikacji na Androida zwykle
do orientacji ekranu.
Obrót zdjęcia można pobrać w jednej z następujących opcji: sposoby:
ImageProxy
val rotation = imageProxy.imageInfo.rotationDegrees
File
val exif = Exif.createFromFile(file) val rotation = exif.rotation
OutputStream
val byteArray = outputStream.toByteArray() val exif = Exif.createFromInputStream(ByteArrayInputStream(byteArray)) val rotation = exif.rotation
MediaStore uri
val inputStream = contentResolver.openInputStream(outputFileResults.savedUri) val exif = Exif.createFromInputStream(inputStream) val rotation = exif.rotation
Sprawdzanie obrotu obrazu
Przypadki użycia ImageAnalysis
i ImageCapture
otrzymują zdarzenia ImageProxy
z metody
z aparatu po pomyślnym żądaniu przechwytywania. ImageProxy
zawija obraz i
informacji o nim, w tym o jego rotacji. Te informacje o rotacji
przedstawia stopnie obrotu obrazu w celu dopasowania do zastosowania
docelową rotację.
Wskazówki dotyczące rotacji celów w przypadku przechwytywania obrazów i analizy obrazów
Ponieważ wiele urządzeń nie obraca się do pozycji pionowej lub poziomej, domyślnie, niektóre aplikacje na Androida nie obsługują tych orientacji. Określa, czy aplikacja obsługuje ją lub nie zmienia sposobu, w jaki rotacja docelowa przypadków użycia może być Zaktualizowano.
Poniżej znajdują się 2 tabele, które określają, jak zsynchronizować rotację docelową w przypadkach użycia. dzięki obróceniu wyświetlacza. Pierwszy pokazuje, jak to robić, a jednocześnie wspiera wszystkie w czterech orientacjach, drugi obsługuje tylko orientacje, w których obraca się urządzenie domyślnie.
Aby wybrać wytyczne, których należy przestrzegać w aplikacji:
Sprawdź, czy aparat
Activity
w aplikacji ma zablokowane ustawienie orientacji. jest odblokowane lub zastępuje zmiany konfiguracji orientacji.Określ, czy kamera aplikacji
Activity
powinna obsługiwać wszystkie 4 urządzenia orientacjami (pionowa, odwrócona pionowa, pozioma i odwrócona pozioma), lub obsługuje tylko orientacje, na których działa. domyślnie.
Obsługa wszystkich 4 orientacji
W tej tabeli podano określone wskazówki, których należy przestrzegać w przypadku, gdy urządzenie nie zostanie odwrócona do orientacji pionowej. To samo można zastosować na urządzeniach, które i nie obracaj kamery w odwrotnej orientacji poziomej.
Scenariusz | Wskazówki | Tryb jednego okna | Tryb podzielonego ekranu dla wielu okien |
---|---|---|---|
Odblokowana orientacja |
Skonfiguruj przypadki użycia co
podczas tworzenia Activity , na przykład w
Activity – połączenie zwrotne (onCreate() ).
|
||
Użyj OrientationEventListener
onOrientationChanged()
W wywołaniu zwrotnym zaktualizuj docelową rotację przypadków użycia. To dotyczy przypadków, w których system nie
odtworzyć Activity nawet po zmianie orientacji, takiej jak
tak jak przy obróceniu urządzenia o 180 stopni.
|
Działa również wtedy, gdy wyświetlacz jest odwrócony do orientacji pionowej, a urządzenie nie obraca się do tyłu wartość domyślną. |
Obsługuje również przypadki, w których Activity nie jest
odtwarzane podczas obrotu urządzenia (np. o 90 stopni). To się dzieje w
na małych urządzeniach, gdy aplikacja zajmuje połowę ekranu i na większym ekranie
gdy aplikacja zajmuje 2/3 ekranu.
|
|
Opcjonalnie: ustaw właściwość screenOrientation aplikacji Activity
usługę do fullSensor w: AndroidManifest
.
|
Dzięki temu interfejs może być ustawiony pionowo, gdy urządzenie jest odwrócone.
pionową i umożliwia odtworzenie obiektu Activity przez
po obróceniu urządzenia o 90 stopni.
|
Nie ma wpływu na urządzenia, które nie obracają się do orientacji pionowej wartość domyślną. Tryb wielu okien nie jest obsługiwany, gdy wyświetlacz jest do odwrotnej orientacji pionowej. | |
Blokada orientacji |
Skonfiguruj przypadki użycia tylko raz, gdy
Aplikacja Activity jest tworzona po raz pierwszy, np. w Activity
onCreate() oddzwonienie.
|
||
Użyj OrientationEventListener
onOrientationChanged()
W wywołaniu zwrotnym zaktualizuj docelową rotację przypadków użycia z wyjątkiem podglądu.
|
Obsługuje również przypadki, w których Activity nie jest
odtwarzane podczas obrotu urządzenia (np. o 90 stopni). To się dzieje w
na małych urządzeniach, gdy aplikacja zajmuje połowę ekranu i na większym ekranie
gdy aplikacja zajmuje 2/3 ekranu.
|
||
Zmiana orientacji orientacji została zastąpiona |
Skonfiguruj przypadki użycia tylko raz, gdy
Aplikacja Activity jest tworzona po raz pierwszy, np. w Activity
onCreate() oddzwonienie.
|
||
Użyj OrientationEventListener
onOrientationChanged()
W wywołaniu zwrotnym zaktualizuj docelową rotację przypadków użycia.
|
Obsługuje również przypadki, w których Activity nie jest
odtwarzane podczas obrotu urządzenia (np. o 90 stopni). To się dzieje w
na małych urządzeniach, gdy aplikacja zajmuje połowę ekranu i na większym ekranie
gdy aplikacja zajmuje 2/3 ekranu.
|
||
Opcjonalnie: ustaw właściwość screenOrientation aktywności na fullSensor w: w pliku AndroidManifest. | Pozwala ustawić interfejs użytkownika pionowo, gdy urządzenie jest ustawione pionowo. | Nie ma wpływu na urządzenia, które nie obracają się do orientacji pionowej wartość domyślną. Tryb wielu okien nie jest obsługiwany, gdy wyświetlacz jest do odwrotnej orientacji pionowej. |
Obsługuj tylko orientacje obsługiwane przez urządzenie
Obsługują tylko orientacje, które urządzenie obsługuje domyślnie (które mogą nie może zawierać odwróconej orientacji pionowej lub poziomej).
Scenariusz | Wskazówki | Tryb podzielonego ekranu dla wielu okien |
---|---|---|
Odblokowana orientacja |
Skonfiguruj przypadki użycia co
podczas tworzenia Activity , na przykład w
Activity – połączenie zwrotne (onCreate() ).
|
|
Użyj DisplayListener
onDisplayChanged() Wewnątrz
z wywołaniem zwrotnym, zaktualizuj docelową rotację przypadków użycia, np. gdy
obrócono urządzenie o 180 stopni.
|
Obsługuje również przypadki, w których Activity nie jest
odtwarzane podczas obrotu urządzenia (np. o 90 stopni). To się dzieje w
na małych urządzeniach, gdy aplikacja zajmuje połowę ekranu i na większym ekranie
gdy aplikacja zajmuje 2/3 ekranu.
|
|
Blokada orientacji |
Skonfiguruj przypadki użycia tylko raz, gdy
Aplikacja Activity jest tworzona po raz pierwszy, np. w Activity
onCreate() oddzwonienie.
|
|
Użyj OrientationEventListener
onOrientationChanged()
W wywołaniu zwrotnym zaktualizuj docelową rotację przypadków użycia.
|
Obsługuje również przypadki, w których Activity nie jest
odtwarzane podczas obrotu urządzenia (np. o 90 stopni). To się dzieje w
na małych urządzeniach, gdy aplikacja zajmuje połowę ekranu i na większym ekranie
gdy aplikacja zajmuje 2/3 ekranu.
|
|
Zmiana orientacji orientacji została zastąpiona |
Skonfiguruj przypadki użycia tylko raz, gdy
Aplikacja Activity jest tworzona po raz pierwszy, np. w Activity
onCreate() oddzwonienie.
|
|
Użyj DisplayListener
onDisplayChanged() Wewnątrz
z wywołaniem zwrotnym, zaktualizuj docelową rotację przypadków użycia, np. gdy
obrócono urządzenie o 180 stopni.
|
Obsługuje również przypadki, w których Activity nie jest
odtwarzane podczas obrotu urządzenia (np. o 90 stopni). To się dzieje w
na małych urządzeniach, gdy aplikacja zajmuje połowę ekranu i na większym ekranie
gdy aplikacja zajmuje 2/3 ekranu.
|
Odblokowana orientacja
Urządzenie Activity
ma otwartą orientację, gdy ma orientację wyświetlacza
(np. pionową lub poziomą) pasuje do fizycznej orientacji urządzenia, przy czym wartość
z wyjątkiem orientacji odwróconej orientacji pionowej i poziomej, których niektóre urządzenia nie obsługują
domyślnie. Aby wymusić obrót urządzenia we wszystkich czterech orientacjach, ustaw
Activity
na fullSensor
.screenOrientation
na urządzeniu w trybie wielu okien, które nie obsługuje odwrotnego trybu pionowego ani poziomego;
domyślnie nie zostanie odwrócona do orientacji pionowej/poziomej, nawet jeśli
Właściwość screenOrientation
jest ustawiona na fullSensor
.
<!-- The Activity has an unlocked orientation, but might not rotate to reverse portrait/landscape in single-window mode if the device doesn't support it by default. --> <activity android:name=".UnlockedOrientationActivity" /> <!-- The Activity has an unlocked orientation, and will rotate to all four orientations in single-window mode. --> <activity android:name=".UnlockedOrientationActivity" android:screenOrientation="fullSensor" />
Zablokowana orientacja
Wyświetlacz ma zablokowaną orientację, gdy pozostaje w tej samej orientacji
(np. pionową lub poziomą) niezależnie od fizycznej orientacji
urządzenia. Można to zrobić, określając właściwość screenOrientation
elementu Activity
właściwości zawartej w deklaracji w pliku AndroidManifest.xml
.
Gdy wyświetlacz jest w zablokowanej orientacji, system nie zniszczy ani nie uszkodzi
Odtwórz Activity
podczas obracania urządzenia.
<!-- The Activity keeps a portrait orientation even as the device rotates. --> <activity android:name=".LockedOrientationActivity" android:screenOrientation="portrait" />
Zastąpiono zmiany konfiguracji orientacji
Gdy Activity
zastąpi konfigurację orientacji, system
nie zniszczy go i nie tworzy ponownie, gdy zmieni się orientacja fizyczna urządzenia.
System aktualizuje interfejs, aby dopasować się do fizycznej orientacji urządzenia.
<!-- The Activity's UI might not rotate in reverse portrait/landscape if the device doesn't support it by default. --> <activity android:name=".OrientationConfigChangesOverriddenActivity" android:configChanges="orientation|screenSize" /> <!-- The Activity's UI will rotate to all 4 orientations in single-window mode. --> <activity android:name=".OrientationConfigChangesOverriddenActivity" android:configChanges="orientation|screenSize" android:screenOrientation="fullSensor" />
Konfiguracja przypadków użycia aparatu
W przypadkach opisanych powyżej przypadki użycia kamery można skonfigurować, gdy
Utworzono Activity
.
W przypadku urządzenia Activity
z odblokowaną orientacją konfiguracja jest gotowa.
przy każdym obróceniu urządzenia, bo system niszczy i tworzy
Activity
o zmianach orientacji. W efekcie przypadki użycia ustawiają
docelowy obrót, aby domyślnie pasował do orientacji wyświetlacza.
W przypadku elementu Activity
z zablokowaną orientacją lub zastąpieniem
konfiguracji orientacji, konfiguracja odbywa się raz, gdy Activity
został utworzony po raz pierwszy.
class CameraActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val cameraProcessFuture = ProcessCameraProvider.getInstance(this) cameraProcessFuture.addListener(Runnable { val cameraProvider = cameraProcessFuture.get() // By default, the use cases set their target rotation to match the // display’s rotation. val preview = buildPreview() val imageAnalysis = buildImageAnalysis() val imageCapture = buildImageCapture() cameraProvider.bindToLifecycle( this, cameraSelector, preview, imageAnalysis, imageCapture) }, mainExecutor) } }
Konfiguracja OrientationEventListener
Użycie parametru OrientationEventListener
umożliwia ciągłe aktualizowanie wartości docelowej
lub obracania aparatu wraz ze zmianą orientacji urządzenia.
class CameraActivity : AppCompatActivity() { private val orientationEventListener by lazy { object : OrientationEventListener(this) { override fun onOrientationChanged(orientation: Int) { if (orientation == ORIENTATION_UNKNOWN) { return } val rotation = when (orientation) { in 45 until 135 -> Surface.ROTATION_270 in 135 until 225 -> Surface.ROTATION_180 in 225 until 315 -> Surface.ROTATION_90 else -> Surface.ROTATION_0 } imageAnalysis.targetRotation = rotation imageCapture.targetRotation = rotation } } } override fun onStart() { super.onStart() orientationEventListener.enable() } override fun onStop() { super.onStop() orientationEventListener.disable() } }
Konfiguracja DisplayListener
Użycie elementu DisplayListener
umożliwia zaktualizowanie docelowego obrotu kamery
przypadków użycia w określonych sytuacjach, na przykład gdy system nie zniszczy
i odtwórz element Activity
po obróceniu urządzenia o 180 stopni.
class CameraActivity : AppCompatActivity() { private val displayListener = object : DisplayManager.DisplayListener { override fun onDisplayChanged(displayId: Int) { if (rootView.display.displayId == displayId) { val rotation = rootView.display.rotation imageAnalysis.targetRotation = rotation imageCapture.targetRotation = rotation } } override fun onDisplayAdded(displayId: Int) { } override fun onDisplayRemoved(displayId: Int) { } } override fun onStart() { super.onStart() val displayManager = getSystemService(Context.DISPLAY_SERVICE) as DisplayManager displayManager.registerDisplayListener(displayListener, null) } override fun onStop() { super.onStop() val displayManager = getSystemService(Context.DISPLAY_SERVICE) as DisplayManager displayManager.unregisterDisplayListener(displayListener) } }