二维码的扫描和生成(zxing-android-embedded)的基础使用

简述:这个博客主要记载zxing-android-embedded的简单使用,如何替换相机的布局,如何去掉生成二维码的空白等等一系列问题.

zxing-android-embedded的使用

  1.首先添加依赖

    implementation 'com.android.support:appcompat-v7:26.1.0'
    implementation 'com.journeyapps:zxing-android-embedded:3.6.0'

2.生成二维码

    private void createQrCode(){
        BarcodeEncoder barcodeEncoder = new BarcodeEncoder();
        try {
            BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, 400, 400);
            bitMatrix =deleteWhite(bitMatrix); //删除二维码周边的空白处 
            qrCodeBitmap=barcodeEncoder.createBitmap(bitMatrix);
            qrCodeImg.setImageBitmap(qrCodeBitmap);
        } catch (WriterException e) {
            e.printStackTrace();
        }
    }

3.扫描二维码

   /**
     * 扫描二维码
     */
    private void scanQrCode(){
        IntentIntegrator intentIntegrator = new IntentIntegrator(this);
        intentIntegrator.setDesiredBarcodeFormats(IntentIntegrator.QR_CODE); //设置扫描的类型
        intentIntegrator.setOrientationLocked(false);  //方向锁定
        intentIntegrator.setCaptureActivity(CustomCaptureActivity.class);
        intentIntegrator.setCameraId(0); //前置相机还是后置相机
        intentIntegrator.setBeepEnabled(false); //是否发出成功的声音
        intentIntegrator.setBarcodeImageEnabled(true);
        intentIntegrator.initiateScan();
    }

方向锁定的话,你还需要设置CaptureActivity,假如你是按依赖添加的而不是导入源码,那么需要

public class CustomCaptureActivity extends CaptureActivity {
}

在AndroidManifest里面设置

<activity android:name=".custom.CustomCaptureActivity"
            android:screenOrientation="fullSensor"
            tools:replace="screenOrientation"/>

在扫描完成之后,他会自动返回到onActivityResult()函数里面

  @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        IntentResult result = IntentIntegrator.parseActivityResult(requestCode, resultCode, data);
        if(result != null) {
            if(result.getContents() == null) {
                Toast.makeText(this, "Cancelled", Toast.LENGTH_LONG).show();
            } else {
                Toast.makeText(this, "Scanned: " + result.getContents(), Toast.LENGTH_LONG).show();
            }
        } else {
            super.onActivityResult(requestCode, resultCode, data);
        }
    }

这里的result.getContents()就是二维码内含的值


删除二维码生成时候的周围的空白

zing-android-embedde原始生成的二维码周围会有很多的空白,所以自己需要删除空白

 /**
     * 删除二维码的空白区域
     * @param matrix
     * @return
     */
    private static BitMatrix deleteWhite(BitMatrix matrix)
    {
        int[] rec = matrix.getEnclosingRectangle();
        //数字7 代表了留的空白区域的大小
        int resWidth = rec[2] + 10;
        int resHeight = rec[3] + 10;
        BitMatrix resMatrix = new BitMatrix(resWidth, resHeight);
        resMatrix.clear();
        for (int i = 10; i < resWidth; i++)
        {
            for (int j = 10; j < resHeight; j++)
            {
                if(matrix.get(i+rec[0],j+rec[1]))
                    resMatrix.set(i,j);
            }
        }
        return resMatrix;
    }


自定义二维码扫描时候扫描的大小

因为zxing-android-embedded生成的界面比较难看,所以一般需要修改原生的界面。一般是修改源码或者是继承

本文因为是采用依赖导成jar进来的,所以采用的是继承的方式。

public class CustomCaptureActivity extends CaptureActivity {

    private ImageView oldBackImg;

    private CustomDecoratedBarcodeView customDecoratedBarcodeView;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        oldBackImg = findViewById(R.id.oldBackImg);
        oldBackImg.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                finish();
            }
        });
    }

    @Override
    protected DecoratedBarcodeView initializeContent(){
        setContentView(R.layout.custom_activity_zxing_capture);
        customDecoratedBarcodeView= findViewById(R.id.zxing_custom_barcode_scanner);
        return customDecoratedBarcodeView;
    }
}

最主要的是inittializeContent()方法,这个方法可以设置除了扫描以外的界面,比如加一个标题栏等等

DecoratedBarcodeView 就是扫描最重要的组成部分,他由两个View组成,第一个BarcodeView就是扫描的窗口,

第二个Viewfinder有效果。 所以我们如果想绘制扫描的界面可以重写Viewfineder的onDraw()方法

package backup.wingos.com.wingbackup.custom;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;

import com.journeyapps.barcodescanner.ViewfinderView;

import backup.wingos.com.wingbackup.R;

/**
 * Created by xiongbo on 2018/11/14.
 */

public class CustomViewfinderView extends ViewfinderView {

    private static  final String TAG = "CustomViewfinderView";

    /**
     * 画相机四个角落的值
     */
    private Paint customPaint;
    /**
     * 获取相机的区域
     */
    private Rect frame;
    /**
     * 修改这个值 可以修改角落绘制的颜色
     */
    private int color;
    /**
     * 四个角落的宽度
     */
    private int cornerWidth;
    /**
     * 四个角落的厚度
     */
    private int cornerHeight;
    /**
     * 你需要在相机下面显示的文字
     */
    private String text;
    /**
     * 中间横线竖直的位置
     */
    private int direction;
    /**
     * 代表了第一次绘制
     */
    private boolean isFirst;
    /**
     * 是否获取二维码的结果
     */
    private boolean isResult;
    /**
     * 是否退出线程
     */
    private boolean isExit;

    private Thread thread;

    public CustomViewfinderView(Context context, AttributeSet attrs) {
        super(context, attrs);
        customPaint = new Paint();
        customPaint.setStyle(Paint.Style.FILL);
        color=getResources().getColor(R.color.colorPrimary);
        customPaint.setAntiAlias(true);
        cornerWidth=50;
        cornerHeight=8;
        text="Scan the QR code from new phone";
        isFirst = true;
        isResult=false;
        isExit=false;
        thread = new Thread(new Runnable() {
            @Override
            public void run() {
                while(!isExit){
                    setDirection(direction+2);
                    try {
                        thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
        thread.start();
    }

    @Override
    public void onDraw(Canvas canvas) {
        super.refreshSizes();
        if (framingRect == null || previewFramingRect == null) {
            return;
        }
        frame = framingRect;
        if(isFirst){
            isFirst=false;
            direction=frame.top+10;
        }
        customPaint.setColor(color);
        customPaint.setStrokeWidth((float) 1.5);
        /**
         * 绘制四条边框
         */
        canvas.drawLine(frame.left,frame.top,frame.right,frame.top,customPaint);
        canvas.drawLine(frame.left,frame.top,frame.left,frame.bottom,customPaint);
        canvas.drawLine(frame.right,frame.top,frame.right,frame.bottom,customPaint);
        canvas.drawLine(frame.right,frame.bottom,frame.left,frame.bottom,customPaint);

        final int width = canvas.getWidth();
        final int height = canvas.getHeight();
        // 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);

        if (resultBitmap != null) {
            // Draw the opaque result bitmap over the scanning rectangle
            paint.setAlpha(CURRENT_POINT_OPACITY);
            canvas.drawBitmap(resultBitmap, null, frame, paint);
            isResult=true;
        } else {
            customPaint.setAlpha(100);
            Rect rect = new Rect(frame.left,frame.top,frame.right, direction);
            canvas.drawRect(rect,customPaint);
            customPaint.setAlpha(255);
            customPaint.setStrokeWidth(3);
            canvas.drawLine(frame.left,direction,frame.right,direction,customPaint);
            if(direction>=frame.bottom){
                direction=frame.top;
            }
        }
        if(isResult){
            isExit=true;
        }else{
            isExit=false;
        }


        drawCorner(1,canvas);
        drawCorner(2,canvas);
        drawCorner(3,canvas);
        drawCorner(4,canvas);
        drawText(text,canvas);
    }

    public void setColor(int color){
        this.color=color;
        invalidate();
    }

    /**
     * 绘制四个角落 type: 1--左上 2--右上 3--左下 4--右下
     */
    private void drawCorner(int type,Canvas canvas){
        Rect verticalRect=null;
        Rect horizontalRect =null;
        if(type==1){
            horizontalRect = new Rect(frame.left,frame.top,frame.left+cornerWidth,frame.top+cornerHeight);
            verticalRect = new Rect(frame.left,frame.top,frame.left+cornerHeight,frame.top+cornerWidth);
        }else if(type==2){
            horizontalRect = new Rect(frame.right-cornerWidth,frame.top,frame.right,frame.top+cornerHeight);
            verticalRect = new Rect(frame.right-cornerHeight,frame.top,frame.right,frame.top+cornerWidth);
        }else if(type==3){
            horizontalRect = new Rect(frame.left,frame.bottom-cornerWidth,frame.left+cornerHeight,frame.bottom);
            verticalRect = new Rect(frame.left,frame.bottom-cornerHeight,frame.left+cornerWidth,frame.bottom);
        }else{
            horizontalRect = new Rect(frame.right-cornerWidth,frame.bottom-cornerHeight,frame.right,frame.bottom);
            verticalRect = new Rect(frame.right-cornerHeight,frame.bottom-cornerWidth,frame.right,frame.bottom);
        }
        canvas.drawRect(horizontalRect,customPaint);
        canvas.drawRect(verticalRect,customPaint);
    }

    public void setText(String text){
        this.text=text;
    }

    private void drawText(String text,Canvas canvas){
        customPaint.setColor(getResources().getColor(R.color.colorWhite));
        customPaint.setTextSize(50);
        canvas.drawText(text,frame.left-30,frame.bottom+100,customPaint);
    }

    private void setDirection(int direction){
        this.direction=direction;
        invalidate();
    }

    public void stopThread(){
        isExit=true;
        if(thread!=null){
            thread=null;
        }
    }

}
首先我们的framingRect 代表了窗口区域,我们绘制的时候不能绘制在窗口的区域里面,要不然会拦住窗口,因为Viewfinder是绘制在BarcodeView的上方的.修改窗口的大小,其实是有属性的,他们自定义View的style如下


<?xml version="1.0" encoding="UTF-8"?>
<resources>

  <declare-styleable name="zxing_view">
    <attr name="zxing_scanner_layout" format="reference"/>
  </declare-styleable>

  <declare-styleable name="zxing_camera_preview">
    <attr name="zxing_framing_rect_width" format="dimension" /> //窗口大小
    <attr name="zxing_framing_rect_height" format="dimension" />
    <attr name="zxing_use_texture_view" format="boolean" />
    <attr name="zxing_preview_scaling_strategy" format="enum">
      <enum name="centerCrop" value="1" />
      <enum name="fitCenter" value="2" />
      <enum name="fitXY" value="3" />
    </attr>
  </declare-styleable>

  <declare-styleable name="zxing_finder">
    <attr name="zxing_possible_result_points" format="color"/>
    <attr name="zxing_result_view" format="color"/>
    <attr name="zxing_viewfinder_laser" format="color"/>
    <attr name="zxing_viewfinder_mask" format="color"/> //绘制背景的颜色
  </declare-styleable>

</resources>

我们自定义的话,可以把这个style复制到自己项目里面。也可以直接用;只要在BarcodeView设置属性就好了

  <backup.wingos.com.wingbackup.custom.CustomBarcodeView
        android:id="@+id/zxing_custom_barcode_surface"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:zxing_framing_rect_height="240dp"
        app:zxing_framing_rect_width="240dp" />


    <backup.wingos.com.wingbackup.custom.CustomViewfinderView
        android:id="@+id/zxing_custom_viewfinder_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:zxing_viewfinder_mask="#757575" />

这样就完成效果了。而且原生的话,关闭会有一定的延时效果,所以我们可以把这个延时关闭掉,影响用户体验

    /**
     * 造成了延时效果
     * 本来为 2000000000 修改成了 10000000
     */
    @Override
    public void pauseAndWait() {
        CameraInstance instance = getCameraInstance();
        pause();
        long startTime = System.nanoTime();
        while(instance != null && !instance.isCameraClosed()) {
            if(System.nanoTime() - startTime > 10000000) {
                // Don't wait for longer than 2 seconds
                break;
            }
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                break;
            }
        }
    }
这需要在CustomBarcodeView里面修改的,因为原生的BarcodeView在退出的时候会阻塞主线程2s钟。



猜你喜欢

转载自www.cnblogs.com/xiongbo753/p/9963027.html
今日推荐