Android アプリは、縦向きで持つスマートフォンだけでなく、さまざまなフォーム ファクタで実行されます。デスクトップ ウィンドウ機能、接続されたディスプレイ、折りたたみ式デバイスの導入に伴い、カメラアプリは動的なウィンドウ サイズ、さまざまなアスペクト比、外部ハードウェアに対応する必要があります。
電話のロジックが壊れる理由
カメラアプリは、マルチ フォーム ファクタ環境で重大な障害を引き起こす想定をすることがよくあります。
自然な向き
- 前提条件: デバイスの自然な向き
ROTATION_0は常に縦向きである - 現実: タブレット、一部の折りたたみ式デバイスのインナー ディスプレイ、デスクトップ モニターでは、
ROTATION_0は横向きであることが多い - 結果: プレビューが 90 度回転する
センサーの調整
- 前提条件: カメラセンサーの長辺が画面の長辺と一致する
- 現実: サイズ変更可能なウィンドウは正方形または横長にできますが、センサーは固定されたままです(通常は 4:3)。
- 結果: 縦横比が変更されたり、歪んだりしている画像
画面密度とサイズ
- 前提条件: 実行時に画面の密度とサイズが変化しない
- 現実: デスクトップ環境では、ユーザーは自由にウィンドウのサイズを変更できます
- 結果: ドラッグ イベントごとにカメラ セッションを再開すると、ユーザー エクスペリエンスが損なわれ、クラッシュが発生する可能性があります。
解決策 1: システム インテントを使用する
アプリで写真や動画の撮影が必要だが、専用のカスタム カメラ インターフェースは必要ない場合、さまざまなフォーム ファクタに対応する最善の方法は、デバイスにプリインストールされているシステム カメラを起動することです(カメラ インテントを参照)。
システム インテントを使用すると、キャプチャ エクスペリエンス全体がデバイスの OEM が開発したカメラアプリに委任されます。これにより、フォーム ファクタのサポートの複雑さが効果的にアウトソースされます。たとえば、次のような複雑さがアウトソースされます。
組み込みのリサイズと回転のサポート - 折りたたみ式デバイスやタブレットのデフォルトのカメラアプリは、その特定のデバイスの形状を処理するためにメーカーによって明示的に構築されています。アプリは、デバイスが広げられたとき、回転されたとき、マルチ ウィンドウ モードになったときに適切に動作するように設計されています。
高度なハードウェア機能へのアクセス - OEM カメラアプリは、手動で複製することが困難または不可能なハードウェア調整アルゴリズム(夜間モード、HDR、特定のレンズ切り替え)に排他的にアクセスできます。
解決策 2: Jetpack CameraX を使用する
CameraX は、カメラアプリの開発を容易にすることを目的とした Jetpack ライブラリです。CameraX はライフサイクルを認識し、サーフェス指向です。デバイスの折りたたみ、回転、サイズ変更のたびにセンサーの向きとサーフェス サイズを手動で再計算する必要がある Camera2 とは異なり、CameraX はマルチ ウィンドウのサイズ変更時や、アプリが接続されたディスプレイに移動したときに、カメラ セッションの再構成を自動的に処理します。これにより、プレビュー ストリームが途切れたり、引き伸ばされたりすることなく適応します。
PreviewView などのコンポーネントは、折りたたみ式デバイスがカバー画面から内側画面に移行するなど、さまざまな状態にわたってアスペクト比とスケールタイプをインテリジェントに管理します。これにより、デバイス固有の複雑なエッジケースのコレクションではなく、単一の整合性のある実装でさまざまなハードウェアをサポートできます。
作成
Jetpack Compose では、専用の androidx.camera:camera-compose ライブラリを使用します。このライブラリには、Compose のライフサイクル内でサイズ変更、回転、アスペクト比の複雑なジオメトリを処理するために特別に設計された CameraXViewfinder コンポーザブルが用意されています。
CameraXViewfinder コンポーネントは、カメラアプリで最も一般的なエラーの原因を排除します。
- 座標の自動変換 - カメラアプリの構築で最も難しい部分の 1 つは、ユーザーのタップ(画面上の x、y 座標)を、フォーカスと測光のためにカメラセンサーの座標系(0 ~ 1、0 ~ 1 の回転)にマッピングすることです。
CameraXViewfinderは、ウィンドウのサイズ変更やデバイスの折りたたみが行われた場合でも、計算を自動的に処理するCoordinateTransformerを提供します。 - 正しいレイアウト動作 -
SurfaceViewやTextureViewとは異なり、CameraXViewfinderは Compose の z 順序で正しく動作します。アーティファクトをレンダリングすることなく、UI 要素(フォーカス リング、コントロール)をオーバーレイしたり、修飾子(角の丸め、アニメーション)を適用したりできます。 - サイズ変更とアスペクト比:
CameraXViewfinderは内部で中央切り抜きと中央フィットのロジックを処理し、アプリ ウィンドウが標準外のアスペクト比(分割画面やデスクトップ ウィンドウ モードなど)にサイズ変更されたときにプレビューが引き伸ばされないようにします。
View
ビューベースのアプリでは、PreviewView または ViewFinderView を使用します。SurfaceView または TextureView を直接使用する場合は、アスペクト比を計算し、正しい変換行列を自分で適用する必要があります。
解決策 3: 向きとサイズ変更を動的に処理する
プラットフォーム API を直接利用する場合は、デバイスの回転、アクティビティの再起動、アスペクト比に注意してください。
デバイスの回転の使用を停止する
UI レイアウトを決定する際に、Display#getRotation() や物理センサーの向きだけに依存しないでください。
- ウィンドウ指標を使用する -
WindowManager#getCurrentWindowMetrics()を使用してアプリ ウィンドウの幅と高さを比較し、レイアウト(横向き UI と縦向き UI)を決定します。 - 自然な向きを無視する - アプリが横向きのモニターで縦向きのウィンドウに表示される可能性があります。デバイスの向きは UI の境界とは関係ありません。
アクティビティの再起動を回避する
デフォルトの Android の動作では、構成の変更(ウィンドウのサイズ変更など)が発生すると、アプリのアクティビティが破棄されます。カメラアプリの場合、ディスプレイのちらつきや、ビデオ通話中の接続の切断として現れます。
- マニフェストの構成 - マニフェストで構成の変更を宣言して、再起動せずにサイズ変更を処理します。
- 動的更新 -
onConfigurationChanged()で、新しいウィンドウ サイズに合わせてカメラ プレビューのレイアウト パラメータを更新します。
アスペクト比とトリミング
折りたたみ式デバイスやデスクトップ ウィンドウでよくある問題は、4:3 のカメラフィードが 16:9 または 1:1 のウィンドウに強制的に表示されるプレビューの引き伸ばしです。
- ストレッチしない - プレビューとウィンドウのアスペクト比が異なる場合、カメラ バッファをビューの境界に正確に合わせることを強制してはなりません。
- 中央クロップ(推奨): プレビューを拡大縮小してウィンドウの短い方の寸法に合わせて、余分な部分を切り抜きます。これにより、被写体が歪むことなくフレーム全体に収まります。
- 中央に合わせる(代替案): 視野全体を表示することが重要な場合(ドキュメントのスキャンなど)、ウィンドウ内のプレビューをレターボックス表示にします。
- 中央に合わせる(代替案): 視野全体を表示することが重要な場合(ドキュメントのスキャンなど)、ウィンドウ内のプレビューをレターボックス表示にします。
ボーナス: 折りたたみ式デバイスを優先したエクスペリエンスのサポート
折りたたみ式デバイスは、単に曲がるスマートフォンではなく、ユーザーが写真や動画を撮影する方法を根本的に改善できる独自のハードウェア状態を提供します。折りたたみ式デバイスの折り目を解決すべき問題として捉えるのではなく、折りたたみ式デバイスでしか実現できない機能を構築するために活用しましょう。
テーブルトップ モード(ハンズフリー撮影)
テーブルトップ モードでは、デバイスを半分に折りたたんで平らな場所に置き、長時間のビデオ通話、タイムラプス撮影、長時間露光の夜間撮影を行うことができます。
背面ディスプレイ モード(高画質の自撮り写真)
- 折りたたみ式デバイスでは、通常、背面カメラの画質はユーザー フェイシング カメラよりも高くなっています。背面ディスプレイ モードでは、デバイスを開いて裏返し、小さなカバー画面をメインの背面カメラのライブ ビューファインダーとして使用できます。
- 背面ディスプレイ モードでは、5,000 万画素以上のセルフィー、超広角のグループ ショット、高品質の Vlog を、追加の機材を持ち運ぶことなく撮影できます。
デュアル スクリーン モード(被写体のプレビュー)
- デュアル スクリーン モードでは、内側と外側の両方の画面にカメラ プレビューを同時に表示できます。人物の撮影に最適です。撮影者が内側の画面で構図を調整している間、被写体は外側の画面で自分の姿を確認してポーズを調整できます。
- リアディスプレイ モード(アプリ全体を移動する)とは異なり、デュアル スクリーン モードでは、カバー画面にセカンダリ プレゼンテーション ウィンドウが作成されます。