Flutter替换CameraPreview为Texture组件时相机预览过度缩放问题
问题核心原因
CameraPreview组件内部自带适配逻辑:会自动读取相机输出的原始宽高比,给内部承载预览的纹理设置匹配原始比例的默认布局尺寸,你外层写死1.7倍缩放刚好把比例正确的预览放大到全屏,所以显示正常。- 裸
Texture组件没有内置这层比例适配,默认会撑满父组件传递的所有可用布局空间。相当于纹理内容先被拉伸到了Transform子组件的最大布局尺寸,你再套1.7倍缩放就等于二次放大,必然出现过度放大的问题。 - 你贴的原生侧创建Surface的代码本身没有错误,问题出在Flutter层两端组件的布局逻辑不一致。
解决方案
方案1:Flutter层手动约束Texture比例(和CameraPreview逻辑完全对齐,推荐)
不要直接把Texture放在Center里,先强制约束它的宽高比和相机原始预览输出完全一致,再做缩放适配,同时不要硬编码缩放值,自动计算适配不同屏幕:
- 先获取相机原始预览尺寸,计算正确宽高比:
// 如果用官方camera插件,直接从控制器拿预览尺寸即可 final previewSize = controller!.value.previewSize!; // 注意根据相机传感器方向调整,若显示比例颠倒就取倒数 final cameraAspectRatio = previewSize.width / previewSize.height;
- 用
AspectRatio组件给Texture加比例约束,再动态计算缩放值实现全屏无拉伸:
LayoutBuilder( builder: (context, constraints) { final screenSize = MediaQuery.of(context).size; // 自动计算铺满全屏需要的缩放值,替代硬编码的1.7 final scale = screenSize.aspectRatio > cameraAspectRatio ? screenSize.width / (screenSize.height * cameraAspectRatio) : screenSize.height / (screenSize.width / cameraAspectRatio); return Transform.scale( scale: scale, child: Center( child: AspectRatio( aspectRatio: cameraAspectRatio, child: Texture(textureId: textureId), ), ), ); }, )
调试提示:如果发现比例不对,直接把
cameraAspectRatio取倒数即可,和你之前CameraPreview正常显示时的比例对齐就行。
方案2:原生侧补全纹理配置(自定义原生相机链路适用)
如果你是自己实现原生相机采集逻辑,没有依赖官方camera插件,需要在Android端给SurfaceTexture设置和相机输出一致的默认缓冲大小,否则Flutter层拿不到纹理的正确原始尺寸:
// 先获取相机支持的预览输出尺寸,以Camera2为例 StreamConfigurationMap configs = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); Size previewSize = configs.getOutputSizes(SurfaceTexture.class)[0]; // 给纹理设置对应缓冲大小,和官方camera插件实现逻辑一致 primaryTexture.surfaceTexture().setDefaultBufferSize(previewSize.getWidth(), previewSize.getHeight()); Surface primarySurface = new Surface(primaryTexture.surfaceTexture());
配置完成后,Flutter层的Texture组件会识别到纹理的正确原始比例,不会出现默认撑满拉伸的问题,再套缩放逻辑就和CameraPreview效果完全一致。
内容的提问来源于stack exchange,提问作者Captivity
相关产品推荐
相关产品推荐

