Android 应用不仅能在纵向模式下运行,还能在更多设备规格上运行。 随着桌面窗口化模式、连接的显示屏和可折叠设备的推出,您的相机应用必须适应动态窗口大小、不同的宽高比和外部硬件。
手机逻辑为何会中断
相机应用通常会做出一些假设,这些假设会导致多设备规格环境出现严重故障。
自然屏幕方向
- 假设: 设备的自然屏幕方向
ROTATION_0始终为 纵向 - 实际情况: 在平板电脑、某些可折叠设备的内屏和桌面显示器上,
ROTATION_0通常为横向 - 结果: 预览错误地旋转了 90 度
传感器对齐
- 假设: 相机传感器的长边与屏幕的长边对齐
- 实际情况: 可调整大小的窗口可以是方形或横向,而传感器保持固定(通常为 4:3)
- 结果: 图片拉伸或以其他方式扭曲
屏幕密度和尺寸
- 假设: 屏幕的密度和尺寸在运行时不会发生变化
- 实际情况: 在桌面环境中,用户可以自由调整窗口大小
- 结果: 在每次拖动事件时重启相机会话会中断用户体验,并可能导致崩溃
解决方案 1:使用系统 intent
如果您的应用需要拍摄照片或视频,但不需要专用的 自定义相机界面,那么处理不同设备规格的最佳方式是 启动设备预安装的系统相机(请参阅相机 intent)
使用系统 intent 会将整个拍摄体验委托给设备原始设备制造商 (OEM) 开发的相机应用。这实际上是将设备规格支持的复杂性“外包”出去,包括:
- 内置调整大小和旋转支持 \- 可折叠设备或平板电脑上的默认相机应用由制造商专门构建,用于处理该特定设备的几何形状。该应用旨在在设备展开、旋转或进入多窗口模式时正常运行。
- 访问高级硬件功能 \- OEM 相机应用可以独占访问硬件调整算法(夜间模式、HDR、特定镜头切换),这些算法很难或无法手动复制。
解决方案 2:使用 Jetpack CameraX
CameraX 是一个 Jetpack 库,旨在帮助简化相机应用开发 。CameraX 具有生命周期感知能力,并且面向 Surface。与 Camera2 不同,Camera2 需要在设备折叠、旋转或调整大小时手动重新计算传感器屏幕方向和 Surface 大小,而 CameraX 会在多窗口模式调整大小期间或应用移至连接的显示屏时自动处理相机会话的重新配置,确保预览流能够自适应,而不会出现卡顿或拉伸。
Components like PreviewView 可以智能地管理不同状态下的宽高比和缩放类型,例如可折叠设备从外屏过渡到内屏,让您能够通过单个一致的实现来支持各种硬件,而不是通过一系列复杂的特定于设备的极端情况。
Compose
借助 Jetpack Compose,可以使用专用的 androidx.camera:camera-compose
库。该库提供了 CameraXViewfinder 可组合项,该可组合项专门用于处理 Compose 生命周期内调整大小、旋转和宽高比的复杂几何形状。
CameraXViewfinder 组件消除了相机应用中最常见的错误来源:
- 自动坐标转换 \- 构建相机应用最难的部分之一是将用户的点按(屏幕上的 x、y 坐标)映射到相机传感器的坐标系(0-1、0-1 旋转)以进行对焦和测光。
CameraXViewfinder提供了一个CoordinateTransformer,它 即使在窗口调整大小或 设备折叠时,也会自动处理数学运算。 - 正确的布局行为 \- 与
SurfaceView或TextureView不同,CameraXViewfinder可以与 Compose 的 z 排序正确搭配使用。您可以叠加界面元素(对焦环、控件)或应用修饰符(圆角、动画),而无需渲染工件。 - 调整大小和宽高比:
CameraXViewfinder在内部处理 中心裁剪与中心适应逻辑,确保在应用窗口调整为非标准宽高比(例如 分屏或桌面窗口化模式)时,预览不会 拉伸。
View
在基于 View 的应用中,请使用 PreviewView 或 ViewFinderView。如果您直接使用
SurfaceView 或 TextureView,则必须自行计算宽高比并
应用正确的 转换矩阵。
解决方案 3:动态处理屏幕方向和调整大小
直接使用 平台 API 时,请注意设备旋转、activity 重启和宽高比。
停止使用设备旋转
请勿仅依赖 Display#getRotation() 或物理传感器方向 alone
来确定界面布局。
- 使用窗口指标 \- 使用
WindowManager#getCurrentWindowMetrics()比较应用窗口的宽度和高度,以确定布局(横向界面与纵向界面 )。 - 忽略自然屏幕方向 \- 您的应用可能位于横向显示器上的纵向窗口中。设备屏幕方向与界面边界无关。
避免重启 activity
默认情况下,Android 会在 配置 更改(例如窗口调整大小)时销毁应用的 activity。对于相机应用,这会显示为视频通话期间的显示屏闪烁或连接断开。
- 清单配置 \- 在清单中声明 配置更改,以便在不重启的情况下处理调整大小。
- 动态更新 \- 在
onConfigurationChanged()中,更新相机 预览的布局参数以匹配新的窗口大小。
宽高比和裁剪
可折叠设备和桌面窗口上的一个常见问题是预览拉伸,即 4:3 摄像头画面被强制放入 16:9 或 1:1 窗口中。
- 不拉伸 \- 如果预览和窗口宽高比不同,切勿强制相机缓冲区与 View 边界完全匹配。
- 中心裁剪(推荐): 缩放预览以填充窗口的最短尺寸,并裁剪多余部分。这可确保拍摄对象保持不失真并填充画面。
- 中心适应(替代方案): 如果显示完整视野范围至关重要(例如扫描文档),请在窗口内将预览设置为信箱模式。
奖励:支持可折叠设备优先体验
可折叠设备不仅仅是可弯曲的手机。它们还提供独特的硬件状态,可以从根本上改善用户拍摄照片和视频的方式。与其将折叠视为要解决的问题,不如利用它来构建在非可折叠设备上无法实现的功能。
桌上模式(免触摸拍摄)
桌上模式允许用户将设备半折叠并将其放在 Surface 上 ,以便进行长时间的视频通话、延时摄影和长曝光夜间 摄影。
后置显示屏模式(高质量自拍)
- 在可折叠设备上,后置摄像头的质量通常高于面向用户的摄像头。后置显示屏模式允许用户展开设备并将其翻转,使用小外屏作为主后置摄像头的实时取景器。
- 借助后置显示屏模式,无需携带额外装备即可拍摄 5000 万像素以上的自拍、超广角合影和高质量视频博客。
双屏幕模式(拍摄对象预览)
- 双屏幕模式让您同时在内屏和外屏上显示相机预览。这非常适合拍摄人物:拍摄对象可以在外屏上看到自己并调整姿势,而您可以在内屏上构图。
- 与后置显示屏模式(移动整个应用)不同,双屏幕模式会在外屏上创建一个辅助演示窗口。