/* * Copyright (C) 2008 ZXing authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.zxing.scanner; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Point; import android.graphics.Rect; import android.graphics.RectF; import android.text.Layout; import android.text.StaticLayout; import android.text.TextPaint; import android.util.AttributeSet; import android.view.View; import com.zxing.scanner.camera.CameraManager; import com.zxing.scanner.common.Scanner; /** * This view is overlaid on top of the camera preview. It adds the viewfinder rectangle and partial * transparency outside it, as well as the laser scanner animation and result points. * * @author dswitkin@google.com (Daniel Switkin) */ final class ViewfinderView extends View { private static final int CURRENT_POINT_OPACITY = 0xA0; private static final int POINT_SIZE = 6; private CameraManager cameraManager; private final Paint paint; private Bitmap resultBitmap; private int animationDelay = 0; private Bitmap laserLineBitmap; private int resultColor = Scanner.color.RESULT_VIEW;//扫描成功后扫描框以外区域白色 private int laserLineTop;// 扫描线最顶端位置 private int laserLineHeight;//扫描线默认高度 private int frameCornerWidth;//扫描框4角宽 private int frameCornerLength;//扫描框4角高 private int tipTextSize;//提示文字大小 private int tipTextMargin;//提示文字与扫描框距离 private ScannerOptions scannerOptions; public ViewfinderView(Context context, AttributeSet attrs) { super(context, attrs); paint = new Paint(Paint.ANTI_ALIAS_FLAG); } void setCameraManager(CameraManager cameraManager) { this.cameraManager = cameraManager; } void setScannerOptions(ScannerOptions scannerOptions) { this.scannerOptions = scannerOptions; laserLineHeight = dp2px(scannerOptions.getLaserLineHeight()); frameCornerWidth = dp2px(scannerOptions.getFrameCornerWidth()); frameCornerLength = dp2px(scannerOptions.getFrameCornerLength()); tipTextSize = Scanner.sp2px(getContext(), scannerOptions.getTipTextSize()); tipTextMargin = dp2px(scannerOptions.getTipTextToFrameMargin()); } private int dp2px(int dp) { return Scanner.dp2px(getContext(), dp); } @Override public void onDraw(Canvas canvas) { if (cameraManager == null) { return; } Rect frame = cameraManager.getFramingRect();//取扫描框 //取屏幕预览 Rect previewFrame = cameraManager.getFramingRectInPreview(); if (frame == null || previewFrame == null) { return; } //全屏不绘制扫描框以外4个区域 if (!scannerOptions.isScanFullScreen()) { drawMask(canvas, frame); } // 如果有二维码结果的Bitmap,在扫取景框内绘制不透明的result Bitmap if (resultBitmap != null) { paint.setAlpha(CURRENT_POINT_OPACITY); canvas.drawBitmap(resultBitmap, null, frame, paint); } else { if (!scannerOptions.isFrameHide()) drawFrame(canvas, frame);//绘制扫描框 if (!scannerOptions.isFrameCornerHide()) drawFrameCorner(canvas, frame);//绘制扫描框4角 drawText(canvas, frame);// 画扫描框下面的字 //全屏移动扫描线 if (scannerOptions.isLaserMoveFullScreen()) { moveLaserSpeedFullScreen(cameraManager.getScreenResolution());//计算全屏移动位置 drawLaserLineFullScreen(canvas, cameraManager.getScreenResolution());//绘制全屏扫描线 } else { drawLaserLine(canvas, frame);//绘制扫描框内扫描线 moveLaserSpeed(frame);//计算扫描框内移动位置 } if (scannerOptions.getViewfinderCallback() != null) { scannerOptions.getViewfinderCallback().onDraw(this, canvas, frame); } } } private void moveLaserSpeed(Rect frame) { //初始化扫描线起始点为扫描框顶部位置 if (laserLineTop == 0) { laserLineTop = frame.top; } int laserMoveSpeed = scannerOptions.getLaserLineMoveSpeed(); // 每次刷新界面,扫描线往下移动 LASER_VELOCITY laserLineTop += laserMoveSpeed; if (laserLineTop >= frame.bottom) { laserLineTop = frame.top; } if (animationDelay == 0) { animationDelay = (int) ((1.0f * 1000 * laserMoveSpeed) / (frame.bottom - frame.top)); } // 只刷新扫描框的内容,其他地方不刷新 postInvalidateDelayed(animationDelay, frame.left - POINT_SIZE, frame.top - POINT_SIZE , frame.right + POINT_SIZE, frame.bottom + POINT_SIZE); } private void moveLaserSpeedFullScreen(Point point) { //初始化扫描线起始点为顶部位置 int laserMoveSpeed = scannerOptions.getLaserLineMoveSpeed(); // 每次刷新界面,扫描线往下移动 LASER_VELOCITY laserLineTop += laserMoveSpeed; if (laserLineTop >= point.y) { laserLineTop = 0; } if (animationDelay == 0) { animationDelay = (int) ((1.0f * 1000 * laserMoveSpeed) / point.y); } postInvalidateDelayed(animationDelay); } /** * 画扫描框外区域 * * @param canvas * @param frame */ private void drawMask(Canvas canvas, Rect frame) { int width = canvas.getWidth(); int height = canvas.getHeight(); paint.setColor(resultBitmap != null ? resultColor : scannerOptions.getFrameOutsideColor()); canvas.drawRect(0, 0, width, frame.top, paint); canvas.drawRect(0, frame.top, frame.left, frame.bottom + 1, paint); canvas.drawRect(frame.right + 1, frame.top, width, frame.bottom + 1, paint); canvas.drawRect(0, frame.bottom + 1, width, height, paint); } /** * 绘制提示文字 * * @param canvas * @param frame */ private void drawText(Canvas canvas, Rect frame) { TextPaint textPaint = new TextPaint(); textPaint.setAntiAlias(true); textPaint.setFlags(Paint.ANTI_ALIAS_FLAG); textPaint.setStyle(Paint.Style.FILL); textPaint.setColor(scannerOptions.getTipTextColor()); textPaint.setTextSize(tipTextSize); float x = frame.left;//文字开始位置 //根据 drawTextGravityBottom 文字在扫描框上方还是上文,默认下方 float y = !scannerOptions.isTipTextToFrameTop() ? frame.bottom + tipTextMargin : frame.top - tipTextMargin; StaticLayout staticLayout = new StaticLayout(scannerOptions.getTipText(), textPaint, frame.width() , Layout.Alignment.ALIGN_CENTER, 1.0f, 0, false); canvas.save(); canvas.translate(x, y); staticLayout.draw(canvas); canvas.restore(); } /** * 绘制扫描框4角 * * @param canvas * @param frame */ private void drawFrameCorner(Canvas canvas, Rect frame) { paint.setColor(scannerOptions.getFrameCornerColor()); paint.setStyle(Paint.Style.FILL); if (scannerOptions.isFrameCornerInside()) { // 左上角,左 canvas.drawRect(frame.left, frame.top, frame.left + frameCornerWidth, frame.top + frameCornerLength, paint); // 左上角,上 canvas.drawRect(frame.left, frame.top, frame.left + frameCornerLength, frame.top + frameCornerWidth, paint); // 右上角,右 canvas.drawRect(frame.right - frameCornerWidth, frame.top, frame.right, frame.top + frameCornerLength, paint); // 右上角,上 canvas.drawRect(frame.right - frameCornerLength, frame.top, frame.right, frame.top + frameCornerWidth, paint); // 左下角,左 canvas.drawRect(frame.left, frame.bottom - frameCornerLength, frame.left + frameCornerWidth, frame.bottom, paint); // 左下角,下 canvas.drawRect(frame.left, frame.bottom - frameCornerWidth, frame.left + frameCornerLength, frame.bottom, paint); // 右下角,右 canvas.drawRect(frame.right - frameCornerWidth, frame.bottom - frameCornerLength, frame.right, frame.bottom, paint); // 右下角,下 canvas.drawRect(frame.right - frameCornerLength, frame.bottom - frameCornerWidth, frame.right, frame.bottom, paint); } else { // 左上角 canvas.drawRect(frame.left - frameCornerWidth, frame.top, frame.left, frame.top + frameCornerLength, paint); canvas.drawRect(frame.left - frameCornerWidth, frame.top - frameCornerWidth, frame.left + frameCornerLength, frame.top, paint); // 右上角 canvas.drawRect(frame.right, frame.top, frame.right + frameCornerWidth, frame.top + frameCornerLength, paint); canvas.drawRect(frame.right - frameCornerLength, frame.top - frameCornerWidth, frame.right + frameCornerWidth, frame.top, paint); // 左下角 canvas.drawRect(frame.left - frameCornerWidth, frame.bottom - frameCornerLength, frame.left, frame.bottom, paint); canvas.drawRect(frame.left - frameCornerWidth, frame.bottom, frame.left + frameCornerLength, frame.bottom + frameCornerWidth, paint); // 右下角 canvas.drawRect(frame.right, frame.bottom - frameCornerLength, frame.right + frameCornerWidth, frame.bottom, paint); canvas.drawRect(frame.right - frameCornerLength, frame.bottom, frame.right + frameCornerWidth, frame.bottom + frameCornerWidth, paint); } } /** * 画扫描框 * * @param canvas * @param frame */ private void drawFrame(Canvas canvas, Rect frame) { paint.setColor(scannerOptions.getFrameStrokeColor());//扫描边框色 paint.setStrokeWidth(scannerOptions.getFrameStrokeWidth()); paint.setStyle(Paint.Style.STROKE); canvas.drawRect(frame, paint); } /** * 画扫描线 * * @param canvas * @param frame */ private void drawLaserLine(Canvas canvas, Rect frame) { if (scannerOptions.getLaserStyle() == ScannerOptions.LaserStyle.COLOR_LINE) { paint.setStyle(Paint.Style.FILL); paint.setColor(scannerOptions.getLaserLineColor());// 设置扫描线颜色 canvas.drawRect(frame.left, laserLineTop, frame.right , laserLineTop + laserLineHeight, paint); } else { if (laserLineBitmap == null)//图片资源文件转为 Bitmap laserLineBitmap = BitmapFactory.decodeResource(getResources(), scannerOptions.getLaserLineResId()); int height = laserLineBitmap.getHeight();//取原图高 //网格图片 if (scannerOptions.getLaserStyle() == ScannerOptions.LaserStyle.RES_GRID) { RectF dstRectF = new RectF(frame.left, frame.top, frame.right, laserLineTop); Rect srcRect = new Rect(0, (int) (height - dstRectF.height()) , laserLineBitmap.getWidth(), height); canvas.drawBitmap(laserLineBitmap, srcRect, dstRectF, paint); } //线条图片 else { //如果没有设置线条高度,则用图片原始高度 if (laserLineHeight == dp2px(ScannerOptions.DEFAULT_LASER_LINE_HEIGHT)) { laserLineHeight = laserLineBitmap.getHeight() / 2; } Rect laserRect = new Rect(frame.left, laserLineTop, frame.right , laserLineTop + laserLineHeight); canvas.drawBitmap(laserLineBitmap, null, laserRect, paint); } } } /** * 画全屏宽扫描线 * * @param canvas * @param point */ private void drawLaserLineFullScreen(Canvas canvas, Point point) { if (scannerOptions.getLaserStyle() == ScannerOptions.LaserStyle.COLOR_LINE) { paint.setStyle(Paint.Style.FILL); paint.setColor(scannerOptions.getLaserLineColor());// 设置扫描线颜色 canvas.drawRect(0, laserLineTop, point.x, laserLineTop + laserLineHeight, paint); } else { if (laserLineBitmap == null)//图片资源文件转为 Bitmap laserLineBitmap = BitmapFactory.decodeResource(getResources(), scannerOptions.getLaserLineResId()); int height = laserLineBitmap.getHeight();//取原图高 //网格图片 if (scannerOptions.getLaserStyle() == ScannerOptions.LaserStyle.RES_GRID) { int dstRectFTop = 0; if (laserLineTop >= height) { dstRectFTop = laserLineTop - height; } RectF dstRectF = new RectF(0, dstRectFTop, point.x, laserLineTop); Rect srcRect = new Rect(0, (int) (height - dstRectF.height()), laserLineBitmap.getWidth(), height); canvas.drawBitmap(laserLineBitmap, srcRect, dstRectF, paint); } //线条图片 else { //如果没有设置线条高度,则用图片原始高度 if (laserLineHeight == dp2px(ScannerOptions.DEFAULT_LASER_LINE_HEIGHT)) { laserLineHeight = laserLineBitmap.getHeight() / 2; } Rect laserRect = new Rect(0, laserLineTop, point.x, laserLineTop + laserLineHeight); canvas.drawBitmap(laserLineBitmap, null, laserRect, paint); } } } void drawViewfinder() { Bitmap resultBitmap = this.resultBitmap; this.resultBitmap = null; if (resultBitmap != null) { resultBitmap.recycle(); } invalidate(); } /** * Draw a bitmap with the result points highlighted instead of the live scanning display. * * @param barcode An image of the decoded barcode. */ void drawResultBitmap(Bitmap barcode) { resultBitmap = barcode; invalidate(); } void laserLineBitmapRecycle() { if (laserLineBitmap != null) { laserLineBitmap.recycle(); laserLineBitmap = null; } } }