Jetpack Compose半透明背景下相机预览适配任意尺寸形状方法
问题
我在半透明背景的Dialog Fragment中放置圆形/正方形样式的相机预览时,遇到了缩放适配问题:
- 缩放类型设为
PreviewView.ScaleType.FIT_CENTER时,预览区域周围存在黑边 - 缩放类型设为
PreviewView.ScaleType.FILL_CENTER时,预览内容会超出预先设定的边界
我当前使用的Camera Preview Composable代码如下:
@Composable private fun CameraPreview( modifier: Modifier = Modifier, scaleType: PreviewView.ScaleType = PreviewView.ScaleType.FILL_CENTER, onUseCase: (UseCase) -> Unit ) { AndroidView( modifier = modifier, factory = { context -> val previewView = PreviewView(context).apply { this.scaleType = scaleType layoutParams = ViewGroup.LayoutParams( ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT ) } onUseCase( Preview.Builder() .build() .also { it.setSurfaceProvider(previewView.surfaceProvider) } ) previewView } ) }
尝试过手动给布局参数设置固定整数值,没有达到预期效果。需要实现的效果是:相机预览完美适配给定边界,既不超出边界范围,也不会在预览周围留下黑边,支持圆形、正方形的显示样式。
解决方案
问题出在两点:一是给PreviewView设置了WRAP_CONTENT布局参数,PreviewView无法正确感知父容器的约束边界;二是直接对PreviewView本身做裁剪/尺寸限制,会因为Surface渲染的特殊机制出现适配异常。
按以下步骤修改即可:
- 缩放类型固定使用
PreviewView.ScaleType.FILL_CENTER,保证相机预览帧等比缩放后完全覆盖可用区域,不会留黑边 - 不要直接给PreviewView设置固定尺寸,在外层套一个父容器,由父容器控制最终的显示尺寸、形状
- 将PreviewView的布局参数改为
MATCH_PARENT,让它填满父容器的所有空间,超出父容器的部分由父容器统一裁剪 - 不要直接裁剪PreviewView,给父容器开启裁剪,圆形/正方形的形状效果也在父容器上设置,避免Surface渲染导致的裁剪失效问题
Compose场景下的实现代码参考:
@Composable private fun CameraPreview( isCircle: Boolean = false, previewSize: Dp = 240.dp, cornerRadius: Dp = 0.dp, onUseCase: (UseCase) -> Unit ) { Box( modifier = Modifier .size(previewSize) .clip( if (isCircle) CircleShape else RoundedCornerShape(cornerRadius) ) ) { AndroidView( modifier = Modifier.fillMaxSize(), factory = { context -> PreviewView(context).apply { scaleType = PreviewView.ScaleType.FILL_CENTER layoutParams = ViewGroup.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT ) val preview = Preview.Builder().build() preview.setSurfaceProvider(surfaceProvider) onUseCase(preview) } } ) } }
如果是原生View体系实现,逻辑完全一致:给PreviewView外层套一个FrameLayout,给FrameLayout设置固定宽高、对应形状的OutlineProvider,开启clipToOutline,PreviewView宽高设为match_parent即可。
内容的提问来源于stack exchange,提问作者Hakshay
相关产品推荐
相关产品推荐

