Android Zxing 扫描器 扫描框、扫描线定制样式

5,313 阅读3分钟

一、概述

相信Adnroid开发都知道,世界上有四款扫描器,ZxingZbarBarcode4JOkapiBarcode 前二者应用较广泛,至于介绍与区别就在此阐述,网上有很多。此文主要介绍在在使用过程中,官方客户端各种达不到需求。相信很多童鞋都有此体会,所以借此机会就在Zxing 官方客户端基础上修改,去除无用功能并二次封装达到可扩展。

  • 官方客户端目前问题汇总
    • 设置功能多余
    • 竖屏后不能正向扫描条形码
    • 扫描框大小、颜色、扫描线配置不够灵活
    • 无生成二维码、主动识别二维码功能
  • 介于以上问题,于是该库就华丽的诞生
    • 修复竖屏不能正向扫描条形码
    • 可定制扫描框与扫描线样式
    • 加入创建二维码、识别图片中的二维码功能

二、效果图

这里写图片描述

本库地址:github.com/mylhyl/Andr…

三、代码说明

定义所用的变量

private int laserColor = Scanner.color.VIEWFINDER_LASER;
private int laserFrameBoundColor = laserColor;
private int laserLineTop;
private int laserLineHeight;
private int laserMoveSpeed;
private int laserFrameCornerWidth;
private int laserFrameCornerLength;
private int laserLineResId;
private String drawText = "将二维码放入框内,即可自动扫描";
private int drawTextSize;
private int drawTextColor = Color.WHITE;
private boolean drawTextGravityBottom = true;
private int drawTextMargin;

darw方法

@Override
public void onDraw(Canvas canvas) {
    if (cameraManager == null) {
        return;
    }
    Rect frame = cameraManager.getFramingRect();
    
    Rect previewFrame = cameraManager.getFramingRectInPreview();
    if (frame == null || previewFrame == null) {
        return;
    }
    
    drawMask(canvas, frame);
    
    if (resultBitmap != null) {
        paint.setAlpha(CURRENT_POINT_OPACITY);
        canvas.drawBitmap(resultBitmap, null, frame, paint);
    } else {
        drawFrame(canvas, frame);
        drawFrameCorner(canvas, frame);
        drawText(canvas, frame);
        drawLaserLine(canvas, frame);
        drawResultPoint(canvas, frame, previewFrame);
        moveLaserSpeed(frame);
    }
}

扫描框的4个角

/**
 * 绘制扫描框4角
 *
 * @param canvas
 * @param frame
 */
private void drawFrameCorner(Canvas canvas, Rect frame) {
    paint.setColor(laserFrameBoundColor);
    paint.setStyle(Paint.Style.FILL);
    
    canvas.drawRect(frame.left - laserFrameCornerWidth, frame.top, frame.left, frame.top
            + laserFrameCornerLength, paint);
    canvas.drawRect(frame.left - laserFrameCornerWidth, frame.top - laserFrameCornerWidth, frame.left
            + laserFrameCornerLength, frame.top, paint);
    
    canvas.drawRect(frame.right, frame.top, frame.right + laserFrameCornerWidth,
            frame.top + laserFrameCornerLength, paint);
    canvas.drawRect(frame.right - laserFrameCornerLength, frame.top - laserFrameCornerWidth,
            frame.right + laserFrameCornerWidth, frame.top, paint);
    
    canvas.drawRect(frame.left - laserFrameCornerWidth, frame.bottom - laserFrameCornerLength,
            frame.left, frame.bottom, paint);
    canvas.drawRect(frame.left - laserFrameCornerWidth, frame.bottom, frame.left
            + laserFrameCornerLength, frame.bottom + laserFrameCornerWidth, paint);
    
    canvas.drawRect(frame.right, frame.bottom - laserFrameCornerLength, frame.right
            + laserFrameCornerWidth, frame.bottom, paint);
    canvas.drawRect(frame.right - laserFrameCornerLength, frame.bottom, frame.right
            + laserFrameCornerWidth, frame.bottom + laserFrameCornerWidth, paint);
}

图片画与画笔扫描线

/**
 * 画扫描线
 *
 * @param canvas
 * @param frame
 */
private void drawLaserLine(Canvas canvas, Rect frame) {
    if (laserLineResId == 0) {
        paint.setStyle(Paint.Style.FILL);
        paint.setColor(laserColor);
        canvas.drawRect(frame.left, laserLineTop, frame.right, laserLineTop + laserLineHeight, paint);
    } else {
        if (laserLineBitmap == null)
            laserLineBitmap = BitmapFactory.decodeResource(getResources(), laserLineResId);
        int height = laserLineBitmap.getHeight();
        
        if (isLaserGridLine) {
            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 == Scanner.dp2px(getContext(), 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 frame
 */
private void drawText(Canvas canvas, Rect frame) {
    int width = canvas.getWidth();
    paint.setColor(drawTextColor);
    paint.setTextSize(drawTextSize);
    final float textWidth = paint.measureText(drawText);
    float x = (width - textWidth) / 2;
    
    float y = drawTextGravityBottom ? frame.bottom + drawTextMargin : frame.top - drawTextMargin;
    canvas.drawText(drawText, x, y, paint);
}

三、使用

直接在layout xml使用ScannerView即可

重写onResume调用mScannerView.onResume();

@Override
protected void onResume() {
    mScannerView.onResume();
    super.onResume();
}

注册扫描成功监听器setOnScannerCompletionListener

/**
 * 扫描成功后将调用
 *
 * @param rawResult    扫描结果
 * @param parsedResult 结果类型
 * @param barcode      扫描后的图像
 */
void OnScannerCompletion(Result rawResult, ParsedResult parsedResult, Bitmap barcode);

调用如下方法获取类型

ParsedResultType type = parsedResult.getType();

可根据type强转为相应的对象,按项目需求处理。每个项目都有不同的需求,所以此库将最终处理结果丢给你们自己咯,想怎么玩就怎么玩,下面代码是在 sample 中

switch (type) {
    case ADDRESSBOOK:
        AddressBookParsedResult addressResult = (AddressBookParsedResult) parsedResult;
        bundle.putStringArray(Intents.AddressBookConnect.NAME, addressResult.getNames());
        bundle.putStringArray(Intents.AddressBookConnect.NUMBER, addressResult.getPhoneNumbers());
        bundle.putStringArray(Intents.AddressBookConnect.EMAIL, addressResult.getEmails());
        break;
    case URI:
        URIParsedResult uriParsedResult = (URIParsedResult) parsedResult;
        bundle.putString(Intents.URIContents.URI, uriParsedResult.getURI());
        break;
    case TEXT:
        bundle.putString(Intents.Scan.RESULT, rawResult.getText());
        break;
}

生成二维码

Bitmap bitmap = QREncode.encodeQR(MainActivity.this,
        new QREncode.Builder()                .setColor(getResources().getColor(R.color.colorPrimary))
                .setParsedResultType(ParsedResultType.URI)
                .setContents("https://github.com/mylhyl")
                .build());
imageView.setImageBitmap(bitmap);

四、样式设置

方法名 说明 默认值
toggleLight 切换闪光灯 关 false
setMediaResId 设置扫描完成播放声音
setLaserFrameBoundColor 扫描框4角颜色 绿色 0xff00ff00
setLaserFrameCornerLength 扫描框4角长度 15dp
setLaserFrameCornerWidth 扫描框4角宽度 2dp
setLaserColor 扫描线颜色 绿色 0xff00ff00
setLaserLineResId 条形扫描线图片资源
setLaserGridLineResId 网格扫描线资源
setLaserLineHeight 扫描线高度 2dp
setLaserFrameSize 设置扫描框大小 屏幕5/8
setLaserFrameTopMargin 设置扫描框与屏幕距离 屏幕5/8-状态
setDrawText text -> 内容
textSize -> 文字大小
textColor -> 文字颜色
isBottom -> 是否在扫描框下方
textMargin -> 离扫描框间距
text -> 将二维码放入框内,即可自动扫描
textSize -> 16sp
textColor -> 白色
isBottom -> true
textMargin -> 20dp