Google ZXing系列讲解(五)——ZXing 仿微信扫描UI

来源:互联网 发布:三维文字制作软件 编辑:程序博客网 时间:2024/06/08 07:55

前言

本篇接续上一篇 Google ZXing系列讲解(四)——ZXing 解决竖屏扫描问题。在上篇文章中,通过zxing官方github中的issue回复,解决了zxing横竖屏都可以扫描条码/二维码问题。
仅仅有这个还是不够酷炫, 若扫描界面能像微信那样就好了, 可以的,少年!
本文目标:
- 探索 ViewfinderView 如何绘制默认UI
- 仿微信定制ZXing UI

少废话,上代码, 戳这里

默认扫描UI

查看zxing源码,自定义这块是在类 ViewfinderView 中实现。主要是在 onDraw方法中处理。
接下来先分析ZXing默认的扫描线,然后再其基础上修改为微信的UI。

默认矩形尺寸的计算

默认横屏扫描界面

这里暂时不考虑图中的菜单等选项。
抽象为坐标图像为:

坐标图像图

这里以横轴演示,左上角为整个手机屏幕的原点,向右延伸为X轴, 向下延伸为Y轴。
ViewfinderView -> onDraw中,先会获取中间frame的尺寸。

Rect frame = cameraManager.getFramingRect();

分析代码发现,ZXing默认的扫描框存在一个范围,最小是240 x 240, 最大的是 1200 x 675, 最大的尺寸是按照 1920 x 1080的 5/8而来的。

  private static final int MAX_FRAME_WIDTH = 1200; // = 5/8 * 1920  private static final int MAX_FRAME_HEIGHT = 675; // = 5/8 * 1080

获得尺寸后,就可以在画布上画出frame的尺寸大小,将周边蒙上阴影!

// Draw the exterior (i.e. outside the framing rect) darkened    paint.setColor(resultBitmap != null ? resultColor : maskColor);    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);

具体的思路按照图上四个区域而来!

默认激光线

// Draw a red "laser scanner" line through the middle to show decoding is active      paint.setColor(laserColor);      paint.setAlpha(SCANNER_ALPHA[scannerAlpha]);      scannerAlpha = (scannerAlpha + 1) % SCANNER_ALPHA.length;      int middle = frame.height() / 2 + frame.top;      canvas.drawRect(frame.left + 2, middle - 1, frame.right - 1, middle + 2, paint);

默认麻点

扫描过程中,会出现麻点,这个是由如下关键代码段处理!

possibleResultPoints = new ArrayList<>(5);        lastPossibleResultPoints = currentPossible;        paint.setAlpha(CURRENT_POINT_OPACITY);        paint.setColor(resultPointColor);        synchronized (currentPossible) {          for (ResultPoint point : currentPossible) {            canvas.drawCircle(frameLeft + (int) (point.getX() * scaleX),                              frameTop + (int) (point.getY() * scaleY),                              POINT_SIZE, paint);          }        }      }

仿微信扫描UI

微信扫描UI,需要修改ViewfinderView 以及添加某些资源文件!先来看下微信扫描UI图。
仿微信扫描框

仿微信扫描框,需要明确以下几个方面:
- 矩形框大小
- 矩形框四角的图形&颜色
- 扫描动画

矩形框大小

横屏时候, ZXing使用了默认的大小 675 x 1200, 而竖屏时候,ZXing使用了默认大小 240 x 240。
关键代码段如下:@CameraManager

public synchronized Rect getFramingRect() {int width = findDesiredDimensionInRange(screenResolution.x, MIN_FRAME_WIDTH, MAX_FRAME_WIDTH);      int height = findDesiredDimensionInRange(screenResolution.y, MIN_FRAME_HEIGHT, MAX_FRAME_HEIGHT);      int leftOffset = (screenResolution.x - width) / 2;      int topOffset = (screenResolution.y - height) / 2;... ...}
private static int findDesiredDimensionInRange(int resolution, int hardMin, int hardMax) {    int dim = 5 * resolution / 8; // Target 5/8 of each dimension    if (dim < hardMin) {      return hardMin;    }    if (dim > hardMax) {      return hardMax;    }    return dim;  }

矩形框四角的图形&颜色

颜色很好确定,画图形的选择有几种方式
- 画8条线
- 画8个矩形

无意中发现这篇文章 一片枫叶专栏, 该作者实现了一个 android-zxingLibrary库,查看该lib中有关画边框的代码,发现使用矩形方式画了8个, 而且使用了AttributeSet来设计,可以在xml中设置边框的宽高等属性! 下文,会做详细说明

扫描动画

上下移动的线条,使用了图片形式。扫描动画原理很简单, onDraw方法被系统不断的调用,在其中控制到上下移动的距离,以及对距离的判断即可!

private void drawScanLight(Canvas canvas, Rect frame) {    if (scanLineTop == 0) {      scanLineTop = frame.top;    }    if (scanLineTop >= frame.bottom - 30) {      scanLineTop = frame.top;    } else {      scanLineTop += SCAN_VELOCITY;// SCAN_VELOCITY可以在属性中设置,默认为5    }    Rect scanRect = new Rect(frame.left, scanLineTop, frame.right, scanLineTop + 30);    canvas.drawBitmap(scanLight, null, scanRect, paint);  }

实现步骤

1.attrs文件

在values目录中添加attrs文件, 参考android-zxingLibrary

<?xml version="1.0" encoding="utf-8"?><resources>    <declare-styleable name="innerrect">        <attr name="inner_width" format="dimension"/>        <attr name="inner_height" format="dimension"/>        <attr name="inner_margintop" format="dimension" />        <attr name="inner_corner_color" format="color" />        <attr name="inner_corner_length" format="dimension" />        <attr name="inner_corner_width" format="dimension" />        <attr name="inner_scan_bitmap" format="reference" />        <attr name="inner_scan_speed" format="integer" />        <attr name="inner_scan_iscircle" format="boolean" />    </declare-styleable></resources>

本文并没有使用到所有属性,这些属性在哪里使用,答案是在 工程目录下的layout-> capture.xml

<com.google.zxing.client.android.ViewfinderView      android:id="@+id/viewfinder_view"      android:layout_width="fill_parent"      android:layout_height="fill_parent"      app:inner_corner_length="30dp" //四角绿颜色矩形的长度      app:inner_corner_width="5dp" //四角绿颜色矩形的宽度      app:inner_scan_bitmap="@drawable/scanline" //需要添加scanline图片到drawable目录中      app:inner_scan_speed="10" // 扫描线移动距离      app:inner_scan_iscircle="true" /> //扫描过程中是否显示麻点

2.ViewfinderView修改

修改了其中很多内容, 涉及的方法包括:
- public ViewfinderView(Context context, AttributeSet attrs)
- private void initInnerRect(Context context, AttributeSet attrs)
- public void onDraw(Canvas canvas)
- private void drawFrameBounds(Canvas canvas, Rect frame)
- private void drawScanLight(Canvas canvas, Rect frame)

关键点都添加了 //add by tan 注释

0 0
原创粉丝点击