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

Flutter使用Texture渲染相机预览画面拉伸如何解决?

Flutter 基于Texture实现相机预览的拉伸变形适配方案

问题背景

直接使用Texture组件承载相机预览流时,错误设置容器宽高比会导致画面严重拉伸,原有问题代码如下:

final size = MediaQuery.of(context).size;
    final deviceRatio = size.width / size.height;
    return Align(
      alignment: Alignment.topCenter,
      child: AspectRatio(
        aspectRatio: deviceRatio,
        child: Stack(
          children: <Widget>[
            CustomPaint(
              foregroundPainter: MeasureFaceOutline(isPosCorrect: true),
              child: Transform(
                alignment: Alignment.center,
                transform: Platform.isIOS ? Matrix4.rotationX(math.pi) : Matrix4.identity(),
                child: Texture(textureId: textureId),
              ),
            ),
          ],
        ),
      ),
    );
  }

已知对照场景:使用官方CameraPreview组件搭配1.7倍缩放时,预览画面显示完全正常,但业务场景要求必须直接使用Texture组件实现预览,需无变形适配方案。

问题根因

画面拉伸的核心原因是错误使用设备屏幕宽高比作为Texture父容器的宽高比,没有对齐相机传感器实际输出的预览帧比例。当容器比例和纹理输出比例不一致时,Texture会默认拉伸填满父容器,直接导致变形。
官方CameraPreview组件本身也是基于Texture封装,内部已经做了比例对齐、动态缩放、裁剪的适配逻辑,我们直接在Texture层复用这套逻辑即可,不需要依赖CameraPreview组件。

适配实现步骤

  • 第一步:获取相机真实输出比例
    相机初始化完成后,从相机控制器实例中读取预览尺寸,计算真实宽高比。注意竖屏场景下Android和iOS平台的预览尺寸宽高方向可能倒置,计算时根据实际显示效果调整宽高顺序即可:
    // 相机初始化完成后取值,不要在初始化未完成时读取
    final previewSize = controller!.value.previewSize!;
    // 竖屏场景下如果比例异常,就把宽高反过来计算:previewSize.height / previewSize.width
    final cameraPreviewRatio = previewSize.width / previewSize.height;
    
  • 第二步:动态计算缩放值,替代硬编码的1.7倍缩放
    不要写死缩放参数,根据屏幕比例和相机预览比例动态计算缩放值,保证画面铺满目标区域的同时不出现比例变形:
    final screenSize = MediaQuery.of(context).size;
    final screenRatio = screenSize.width / screenSize.height;
    final scale = screenRatio / cameraPreviewRatio;
    final finalScale = scale < 1 ? 1 / scale : scale;
    
  • 第三步:调整布局结构,增加裁剪逻辑
    替换原有基于设备比例的AspectRatio配置,外层增加裁剪容器避免缩放后的画面溢出遮挡其他组件,完整可运行代码如下:
    return Align(
      alignment: Alignment.topCenter,
      child: ClipRect(
        child: Transform.scale(
          scale: finalScale,
          alignment: Alignment.center,
          child: AspectRatio(
            aspectRatio: cameraPreviewRatio,
            child: Stack(
              children: <Widget>[
                CustomPaint(
                  foregroundPainter: MeasureFaceOutline(isPosCorrect: true),
                  child: Transform(
                    alignment: Alignment.center,
                    transform: Platform.isIOS ? Matrix4.rotationX(math.pi) : Matrix4.identity(),
                    child: Texture(textureId: textureId),
                  ),
                ),
              ],
            ),
          ),
        ),
      ),
    );
    

适配说明:上述实现逻辑和官方CameraPreview内部的适配逻辑完全一致,不需要引入CameraPreview组件,直接使用Texture即可实现无拉伸、无变形的预览效果,和之前测试正常的缩放版CameraPreview显示效果完全对齐。如果需要适配横屏场景,只需要同步调整预览比例的宽高计算顺序即可。

内容的提问来源于stack exchange,提问作者Captivity

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.01 12:39:50