设备旋转时锁定Camera X预览方向,其余UI正常旋转的实现方案
解决CameraX预览固定方向但其余UI随设备旋转的问题
核心思路
CameraX没有直接提供lockOrientation()这类方法,但可以通过固定Preview的目标旋转角度+控制PreviewView不跟随系统方向变化的组合方式实现需求,同时让Flutter侧正常处理横竖屏UI适配。
一、Android原生(Kotlin)实现步骤
固定Preview的目标旋转角度
初始化Preview时,强制设置固定的目标旋转值(比如始终竖屏用Surface.ROTATION_0,固定横屏用Surface.ROTATION_90),确保CameraX输出的预览帧方向不随设备旋转改变:val preview = Preview.Builder() .setTargetResolution(Size(1920, 1080)) // 根据需求设置分辨率 .setTargetRotation(Surface.ROTATION_0) // 强制固定为竖屏旋转角度 .build()控制PreviewView不跟随系统旋转
XML中设置android:screenOrientation无效(该属性是Activity级别的),需通过代码固定PreviewView的显示方向:// 优先使用SurfaceView实现,避免TextureView的自动旋转行为 cameraView.preferredImplementationMode = PreviewView.ImplementationMode.SURFACE_VIEW // 强制设置PreviewView的显示方向为0(竖屏),与Preview的目标旋转一致 cameraView.setDisplayOrientation(0)在配置变化中跳过PreviewView的更新
重写Activity的onConfigurationChanged,只处理其他UI的横竖屏适配,不修改PreviewView的状态:override fun onConfigurationChanged(newConfig: Configuration) { super.onConfigurationChanged(newConfig) // 此处处理其他原生UI的横竖屏适配(如布局调整、控件重排) // 不要对cameraView做任何旋转或布局修改 }
二、Flutter侧配合处理
Flutter端正常监听设备方向变化,仅更新自身UI布局,无需将方向变化传递给CameraX模块:
import 'package:flutter/services.dart'; @override void initState() { super.initState(); // 监听设备方向变化,调整Flutter UI SystemChannels.lifecycle.setMessageHandler((message) async { if (message == AppLifecycleState.resumed.toString()) { final currentOrientation = await SystemChrome.getPreferredOrientations(); // 根据currentOrientation调整Flutter页面布局(如切换横/竖屏Widget) } return null; }); }
完整Kotlin示例代码
class CameraXController( private val context: Context, private val cameraView: PreviewView ) : LifecycleObserver { private lateinit var cameraProvider: ProcessCameraProvider fun initCamera() { val cameraProviderFuture = ProcessCameraProvider.getInstance(context) cameraProviderFuture.addListener({ cameraProvider = cameraProviderFuture.get() bindCameraPreview() }, ContextCompat.getMainExecutor(context)) } private fun bindCameraPreview() { val preview = Preview.Builder() .setTargetResolution(Size(1920, 1080)) .setTargetRotation(Surface.ROTATION_0) // 固定竖屏 .build() val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA // 固定PreviewView显示方向 cameraView.preferredImplementationMode = PreviewView.ImplementationMode.SURFACE_VIEW cameraView.setDisplayOrientation(0) preview.setSurfaceProvider(cameraView.surfaceProvider) try { cameraProvider.unbindAll() cameraProvider.bindToLifecycle( context as LifecycleOwner, cameraSelector, preview ) } catch (e: Exception) { // 捕获并处理相机绑定异常 } } }
内容的提问来源于stack exchange,提问作者Tom3652
相关产品推荐
相关产品推荐

