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

前言

本篇接续上一篇 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 注释

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值