You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

设备旋转时锁定Camera X预览方向,其余UI正常旋转的实现方案

解决CameraX预览固定方向但其余UI随设备旋转的问题

核心思路

CameraX没有直接提供lockOrientation()这类方法,但可以通过固定Preview的目标旋转角度+控制PreviewView不跟随系统方向变化的组合方式实现需求,同时让Flutter侧正常处理横竖屏UI适配。

一、Android原生(Kotlin)实现步骤

  1. 固定Preview的目标旋转角度
    初始化Preview时,强制设置固定的目标旋转值(比如始终竖屏用Surface.ROTATION_0,固定横屏用Surface.ROTATION_90),确保CameraX输出的预览帧方向不随设备旋转改变:

    val preview = Preview.Builder()
        .setTargetResolution(Size(1920, 1080)) // 根据需求设置分辨率
        .setTargetRotation(Surface.ROTATION_0) // 强制固定为竖屏旋转角度
        .build()
    
  2. 控制PreviewView不跟随系统旋转
    XML中设置android:screenOrientation无效(该属性是Activity级别的),需通过代码固定PreviewView的显示方向:

    // 优先使用SurfaceView实现,避免TextureView的自动旋转行为
    cameraView.preferredImplementationMode = PreviewView.ImplementationMode.SURFACE_VIEW
    // 强制设置PreviewView的显示方向为0(竖屏),与Preview的目标旋转一致
    cameraView.setDisplayOrientation(0)
    
  3. 在配置变化中跳过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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 05:45:41