最近忙成代码狗,一直没时间更新博客,明天就是周末了,在下班前更新一篇近期写的代码。
因为产品需求,一开始调用系统相机,发现很多功能无法实现,只能自定义相机,自己之前自定义了相机,在Camera和Camera2的选择上犹豫了,因为iCamera容易上手,但是过时了,所以后来还是选择Camera2起步,痛苦挣扎了一周,终于实现了,后面会写一篇关于自定义相机的博客。
言归正传,今天分享的是做的一个自定义扫描界面,页面仿ZXing扫描页面,之前没做过,挣扎一下午,自定义了View,话不多说,上代码:
public class AutoScanView extends View { private Paint maskPaint; // 蒙层的笔 private Paint linePaint; // 中间线的笔 private Paint traAnglePaint; // 边角的笔 private Paint textPaint; // 文字的笔 private final int maskColor = Color.parseColor("#60000000"); //蒙在摄像头上面区域的半透明颜色 private final int triAngleColor = Color.parseColor("#76EE00"); //边角的颜色 private final int lineColor = Color.parseColor("#FF0000"); //中间线的颜色 private final int textColor = Color.parseColor("#CCCCCC"); //文字的颜色 private final int triAngleLength = dp2px(20); //每个角的点距离 private final int triAngleWidth = dp2px(4); //每个角的点宽度 private final int textMarinTop = dp2px(36); //文字距离识别框的距离 private int lineOffsetCount = 0; private static final int MIN_FRAME_WIDTH = 240; private static final int MAX_FRAME_WIDTH = 1200; // = 5/8 * 1920 public AutoScanPlateView(Context context) { this(context, null); } public AutoScanPlateView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public AutoScanPlateView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); maskPaint = new Paint(Paint.ANTI_ALIAS_FLAG); maskPaint.setColor(maskColor); traAnglePaint = new Paint(Paint.ANTI_ALIAS_FLAG); traAnglePaint.setColor(triAngleColor); traAnglePaint.setStrokeWidth(triAngleWidth); traAnglePaint.setStyle(Paint.Style.STROKE); linePaint = new Paint(Paint.ANTI_ALIAS_FLAG); linePaint.setColor(lineColor); textPaint = new Paint(Paint.ANTI_ALIAS_FLAG); textPaint.setColor(textColor); textPaint.setTextSize(dp2px(18)); } @Override protected void onDraw(Canvas canvas) { DisplayMetrics dm = getResources().getDisplayMetrics(); int widthPixels = dm.widthPixels;// 屏幕宽 int heightPixels = dm.heightPixels;// 屏幕高 int midWidth = widthPixels / 2; int midHeight = heightPixels / 2; int scanWidth = getScanWidth(widthPixels, MIN_FRAME_WIDTH, MAX_FRAME_WIDTH);// 矩形宽 int scanHeight = scanWidth / 2; // 矩形高 Point midPoint = new Point(midWidth,midHeight); // 中心点 int leftOffset = midPoint.x -( scanWidth / 2); int topOffset = midPoint.y - (scanHeight / 2); Rect frame = new Rect(leftOffset, topOffset, leftOffset + scanWidth, topOffset + scanHeight); int width = canvas.getWidth(); int height = canvas.getHeight(); // 除了中间的识别区域,其他区域都将蒙上一层半透明的图层 canvas.drawRect(0, 0, width, frame.top, maskPaint); canvas.drawRect(0, frame.top, frame.left, frame.bottom + 1, maskPaint); canvas.drawRect(frame.right + 1, frame.top, width, frame.bottom + 1, maskPaint); canvas.drawRect(0, frame.bottom + 1, width, height, maskPaint); String text = "将内容放入框内,即可自动扫描"; canvas.drawText(text, (width - textPaint.measureText(text)) / 2, frame.bottom + textMarinTop, textPaint); // 四个角落的三角 Path leftTopPath = new Path(); leftTopPath.moveTo(frame.left + triAngleLength, frame.top + triAngleWidth / 2); leftTopPath.lineTo(frame.left + triAngleWidth / 2, frame.top + triAngleWidth / 2); leftTopPath.lineTo(frame.left + triAngleWidth / 2, frame.top + triAngleLength); canvas.drawPath(leftTopPath, traAnglePaint); Path rightTopPath = new Path(); rightTopPath.moveTo(frame.right - triAngleLength, frame.top + triAngleWidth / 2); rightTopPath.lineTo(frame.right - triAngleWidth / 2, frame.top + triAngleWidth / 2); rightTopPath.lineTo(frame.right - triAngleWidth / 2, frame.top + triAngleLength); canvas.drawPath(rightTopPath, traAnglePaint); Path leftBottomPath = new Path(); leftBottomPath.moveTo(frame.left + triAngleWidth / 2, frame.bottom - triAngleLength); leftBottomPath.lineTo(frame.left + triAngleWidth / 2, frame.bottom - triAngleWidth / 2); leftBottomPath.lineTo(frame.left + triAngleLength, frame.bottom - triAngleWidth / 2); canvas.drawPath(leftBottomPath, traAnglePaint); Path rightBottomPath = new Path(); rightBottomPath.moveTo(frame.right - triAngleLength, frame.bottom - triAngleWidth / 2); rightBottomPath.lineTo(frame.right - triAngleWidth / 2, frame.bottom - triAngleWidth / 2); rightBottomPath.lineTo(frame.right - triAngleWidth / 2, frame.bottom - triAngleLength); canvas.drawPath(rightBottomPath, traAnglePaint); //循环划线,从上到下 if (lineOffsetCount > frame.bottom - frame.top - dp2px(10)) { lineOffsetCount = 0; } else { lineOffsetCount = lineOffsetCount + 2; // canvas.drawLine(frame.left, frame.top + lineOffsetCount, frame.right, frame.top + lineOffsetCount, linePaint); //画一条红色的线 Rect lineRect = new Rect(); lineRect.left = frame.left; lineRect.top = frame.top + lineOffsetCount; lineRect.right = frame.right; lineRect.bottom = frame.top + dp2px(10) + lineOffsetCount; canvas.drawBitmap(((BitmapDrawable)(getResources().getDrawable(R.mipmap.scanline))).getBitmap(), null, lineRect, linePaint); } postInvalidateDelayed(10L, frame.left, frame.top, frame.right, frame.bottom); } private int getScanWidth(int screemWidth, int min, int max) { int dim = 5 * screemWidth / 8; // 屏幕宽的5/8 if (dim < min) { dim = min; } if (dim > max) { dim = max; } return dim; } private int dp2px(int dp) { float density = getContext().getResources().getDisplayMetrics().density; return (int) (dp * density + 0.5f); } }
这里面很多元素可以自行更改,因为业务需求,我是把扫描框高度减半,大小可自行更改,屏占比参考了ZXing的计算方式。