Android 앱은 세로 모드로 잡은 휴대전화보다 더 많은 폼 팩터에서 실행됩니다. 데스크톱 창 모드, 연결된 디스플레이, 폴더블 기기가 도입됨에 따라 카메라 앱은 동적 창 크기, 다양한 가로세로 비율, 외부 하드웨어에 적응해야 합니다.
전화 로직이 중단되는 이유
카메라 앱은 멀티 폼 팩터 환경에서 심각한 오류를 일으키는 가정을 하는 경우가 많습니다.
자연스러운 방향
- 가정: 기기의 자연스러운 방향
ROTATION_0은 항상 세로 모드입니다. - 실제: 태블릿, 일부 폴더블의 내부 디스플레이, 데스크톱 모니터에서
ROTATION_0는 가로 모드인 경우가 많습니다. - 결과: 미리보기가 90도 잘못 회전됨
센서 정렬
- 가정: 카메라 센서의 긴 모서리가 화면의 긴 모서리와 정렬됩니다.
- 실제: 센서는 고정되어 있지만 (일반적으로 4:3) 크기 조절이 가능한 창은 정사각형 또는 가로 모드일 수 있습니다.
- 결과: 이미지가 늘어나거나 왜곡됨
화면 밀도 및 크기
- 가정: 화면의 밀도와 크기는 런타임에 변경되지 않습니다.
- 사실: 데스크톱 환경에서 사용자는 자유롭게 창 크기를 조절합니다.
- 결과: 드래그 이벤트마다 카메라 세션을 다시 시작하면 사용자 환경이 중단되고 비정상 종료가 발생할 수 있습니다.
솔루션 1: 시스템 인텐트 사용
앱에서 사진이나 동영상을 촬영해야 하지만 특수 맞춤 카메라 인터페이스가 필요하지 않은 경우 다양한 폼 팩터를 처리하는 가장 좋은 방법은 기기의 사전 설치된 시스템 카메라를 실행하는 것입니다 (카메라 인텐트 참고).
시스템 인텐트를 사용하면 전체 캡처 환경이 기기 OEM에서 개발한 카메라 앱에 위임됩니다. 이렇게 하면 다음을 비롯한 폼 팩터 지원의 복잡성이 효과적으로 아웃소싱됩니다.
내장된 크기 조절 및 회전 지원 - 폴더블 또는 태블릿의 기본 카메라 앱은 제조업체에서 해당 특정 기기의 지오메트리를 처리하도록 명시적으로 빌드합니다. 앱은 기기가 펼쳐지거나 회전되거나 멀티 윈도우 모드로 전환될 때 제대로 작동하도록 설계되었습니다.
고급 하드웨어 기능 액세스 - OEM 카메라 앱은 수동으로 복제하기 어렵거나 불가능한 하드웨어 조정 알고리즘 (야간 모드, HDR, 특정 렌즈 전환)에 독점적으로 액세스할 수 있습니다.
솔루션 2: Jetpack CameraX 사용
CameraX는 카메라 앱 개발을 더 쉽게 할 수 있도록 만들어진 Jetpack 라이브러리입니다. CameraX는 수명 주기를 인식하고 표면 지향적입니다. 기기가 접히거나 회전하거나 크기가 조절될 때마다 센서 방향과 화면 크기를 수동으로 다시 계산해야 하는 Camera2와 달리 CameraX는 다중 창 크기 조절 중이나 앱이 연결된 디스플레이로 이동할 때 카메라 세션의 재구성을 자동으로 처리하여 미리보기 스트림이 끊김이나 늘어짐 없이 적응하도록 합니다.
PreviewView와 같은 구성요소는 폴더블이 커버 화면에서 내부 화면으로 전환되는 등 다양한 상태에서 가로세로 비율과 크기 조절 유형을 지능적으로 관리하므로 복잡한 기기별 특이 사례 모음이 아닌 일관된 단일 구현으로 다양한 하드웨어를 지원할 수 있습니다.
Compose
Jetpack Compose를 사용하는 경우 전용 androidx.camera:camera-compose 라이브러리를 사용하세요. 이 라이브러리는 Compose 수명 주기 내에서 크기 조절, 회전, 가로세로 비율의 복잡한 기하학적 구조를 처리하도록 특별히 설계된 CameraXViewfinder 컴포저블을 제공합니다.
CameraXViewfinder 구성요소는 카메라 앱에서 가장 일반적인 오류 소스를 제거합니다.
- 자동 좌표 변환 - 카메라 앱을 빌드할 때 가장 어려운 부분 중 하나는 사용자의 탭 (화면 좌표의 x, y)을 초점 및 측정을 위해 카메라 센서의 좌표 시스템 (0~1, 0~1 회전)에 매핑하는 것입니다.
CameraXViewfinder는 창의 크기가 조절되거나 기기가 접히는 경우에도 수학을 자동으로 처리하는CoordinateTransformer를 제공합니다. - 올바른 레이아웃 동작:
SurfaceView또는TextureView와 달리CameraXViewfinder는 Compose의 z 순서와 올바르게 작동합니다. 아티팩트를 렌더링하지 않고 UI 요소 (포커스 링, 컨트롤)를 오버레이하거나 수정자(모서리 둥글게 하기, 애니메이션)를 적용할 수 있습니다. - 크기 조절 및 가로세로 비율:
CameraXViewfinder는 내부적으로 중앙 자르기 대 중앙 맞추기 로직을 처리하여 앱 창의 크기가 비표준 가로세로 비율(예: 화면 분할 또는 데스크톱 창 모드)로 조정될 때 미리보기가 늘어나지 않도록 합니다.
뷰
뷰 기반 앱에서는 PreviewView 또는 ViewFinderView를 사용합니다.
SurfaceView 또는 TextureView을 직접 사용하는 경우 종횡비를 계산하고 올바른 변환 행렬을 직접 적용해야 합니다.
해결 방법 3: 방향 및 크기 조정을 동적으로 처리
플랫폼 API를 직접 활용할 때는 기기 회전, 활동 다시 시작, 가로세로 비율을 염두에 두세요.
기기 회전 사용 중지
UI 레이아웃을 결정할 때 Display#getRotation() 또는 물리적 센서 방향에만 의존하지 마세요.
- 창 측정항목 사용 -
WindowManager#getCurrentWindowMetrics()을 사용하여 앱 창의 너비와 높이를 비교하여 레이아웃 (가로 모드와 세로 모드 UI)을 결정합니다. - 자연스러운 방향 무시 - 앱이 가로 모니터에서 세로 모양 창에 있을 수 있습니다. 기기 방향은 UI 경계와 관련이 없습니다.
활동 다시 시작 방지
기본 Android 동작은 구성 변경(예: 창 크기 조절) 시 앱의 활동을 소멸시킵니다. 카메라 앱의 경우 디스플레이 깜박임이나 영상 통화 중 연결 끊김으로 표시됩니다.
- 매니페스트 구성 - 다시 시작하지 않고 크기 조절을 처리하려면 매니페스트에서 구성 변경사항을 선언하세요.
- 동적 업데이트 -
onConfigurationChanged()에서 새 창 크기에 맞게 카메라 미리보기의 레이아웃 매개변수를 업데이트합니다.
가로세로 비율 및 자르기
폴더블 및 데스크톱 창에서 흔히 발생하는 문제는 4:3 카메라 피드가 16:9 또는 1:1 창으로 강제 적용되는 미리보기 스트레칭입니다.
- 늘리지 않음 - 미리보기와 창 가로세로 비율이 다른 경우 카메라 버퍼가 뷰 경계와 정확히 일치하도록 강제하지 마세요.
- 중앙 자르기 (권장): 미리보기를 창의 가장 짧은 치수로 조정하고 초과 부분을 자릅니다. 이렇게 하면 피사체가 왜곡되지 않고 프레임을 채울 수 있습니다.
- 중앙 맞춤 (대안): 전체 시야를 표시하는 것이 중요한 경우(예: 문서를 스캔하는 경우) 창 내에서 미리보기를 레터박스 처리합니다.
- 중앙 맞춤 (대안): 전체 시야를 표시하는 것이 중요한 경우(예: 문서를 스캔하는 경우) 창 내에서 미리보기를 레터박스 처리합니다.
보너스: 폴더블 우선 환경 지원
폴더블 기기는 단순히 구부러지는 휴대전화가 아니라 사용자가 사진과 동영상을 촬영하는 방식을 근본적으로 개선할 수 있는 고유한 하드웨어 상태를 제공합니다. 폴드를 해결해야 할 문제로 취급하는 대신 폴드를 사용하여 폴더블 기기에서는 불가능한 기능을 빌드하세요.
테이블탑 모드 (핸즈프리 캡처)
테이블탑 모드를 사용하면 사용자가 기기를 절반으로 접어 표면에 놓고 장시간 영상 통화, 타임랩스 사진, 장노출 야경 사진을 촬영할 수 있습니다.
후면 디스플레이 모드 (고화질 셀카)
- 폴더블 기기에서는 후면 카메라가 일반적으로 사용자 페이싱 카메라보다 품질이 높습니다. 후면 디스플레이 모드를 사용하면 사용자가 기기를 펼치고 돌려 작은 커버 화면을 기본 후면 카메라의 실시간 뷰파인더로 사용할 수 있습니다.
- 후면 디스플레이 모드를 사용하면 추가 장비를 휴대하지 않고도 50MP 이상의 셀카, 초광각 단체 사진, 고품질 브이로그를 촬영할 수 있습니다.
듀얼 화면 모드 (피사체 미리보기)
- 듀얼 화면 모드를 사용하면 내부 및 외부 화면 모두에 카메라 미리보기를 동시에 표시할 수 있습니다. 인물 사진을 촬영할 때 유용합니다. 사진 피사체가 외부 화면에서 자신의 모습을 보면서 포즈를 조정할 수 있고, 촬영자는 내부 화면에서 프레임을 조정할 수 있습니다.
- 전체 앱을 이동하는 후면 디스플레이 모드와 달리 듀얼 화면 모드는 커버 화면에 보조 프레젠테이션 창을 만듭니다.