Android CameraX扫码界面如何绘制居中透明矩形遮罩?
现有代码核心问题
- Paint属性配置错误:
mSemiBlackPaint未设置填充样式Paint.Style.FILL,导致半透明背景绘制异常;单独绘制透明矩形的逻辑完全无效,透明色绘制到Canvas上不会产生任何效果,属于冗余代码。 - 坐标计算错误:
onDraw方法中使用getLeft()/getRight()/getTop()/getBottom()计算矩形坐标是错误的,这几个值是View相对于父布局的位置,Canvas的绘制坐标是View自身的内部坐标,应该使用0、getWidth()、getHeight()来计算。 - 绘制逻辑冗余:同时调用了
canvas.drawPath(mPath, mSemiBlackPaint)和canvas.drawColor()两次绘制半透黑色,属于多余操作,clipPath后的绘制完全没必要。 - 矩形不符合需求:当前计算的矩形不是正方形,也不支持自定义边长或内边距。
修复后完整代码
import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Path; import android.graphics.RectF; import android.util.AttributeSet; import android.view.View; import androidx.annotation.Nullable; public class QROverlay extends View { private final Paint mSemiBlackPaint = new Paint(Paint.ANTI_ALIAS_FLAG); private final Path mPath = new Path(); private RectF mBoxRect = new RectF(); // 两种配置模式:优先使用内边距,内边距为0时使用指定边长 private int mBoxPadding = 0; private int mBoxSideLength = dp2px(240); // 默认边长240dp public QROverlay(Context context) { super(context); init(); } public QROverlay(Context context, @Nullable AttributeSet attrs) { super(context, attrs); init(); } public QROverlay(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } private void init() { mSemiBlackPaint.setStyle(Paint.Style.FILL); mSemiBlackPaint.setColor(Color.parseColor("#A6000000")); // 65%不透明度的黑色 } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); // 计算居中的正方形扫码框 int sideLength; if (mBoxPadding > 0) { sideLength = Math.min(w, h) - 2 * mBoxPadding; } else { sideLength = mBoxSideLength; } // 居中计算坐标 float left = (w - sideLength) / 2f; float top = (h - sideLength) / 2f; float right = left + sideLength; float bottom = top + sideLength; mBoxRect.set(left, top, right, bottom); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); mPath.reset(); mPath.addRect(mBoxRect, Path.Direction.CW); mPath.setFillType(Path.FillType.INVERSE_EVEN_ODD); canvas.drawPath(mPath, mSemiBlackPaint); } // 公开方法:设置扫码框内边距(基于View短边计算) public void setBoxPadding(int paddingPx) { this.mBoxPadding = paddingPx; this.mBoxSideLength = 0; requestLayout(); } // 公开方法:设置扫码框边长 public void setBoxSideLength(int sideLengthPx) { this.mBoxSideLength = sideLengthPx; this.mBoxPadding = 0; requestLayout(); } private int dp2px(float dp) { float density = getContext().getResources().getDisplayMetrics().density; return (int) (dp * density + 0.5f); } }
用法说明
- 如需指定固定边长:调用
setBoxSideLength方法传入边长像素值即可,代码中默认提供了dp转px的工具方法,也可自己传入适配后的像素值。 - 如需按内边距计算边长:调用
setBoxPadding方法传入内边距像素值,会自动基于View的短边计算居中正方形的边长。 - 叠加到CameraX的预览View上时,需要保证QROverlay和预览View大小一致,放在同一个帧布局即可。
内容的提问来源于stack exchange,提问作者Shuba. . S hetty
相关产品推荐
相关产品推荐

