【原创】Android 二维码 zxing-android-embedded的使用以及自定义样式

转载注明出处,否则小jj弹肿,什么?!没有?? 那...嘿嘿嘿~

https://blog.csdn.net/dazhang357/article/details/81559888

最近项目中要使用扫描二维码,于是乎就用到了 zxing-android-embedded 这个由zing库演变过来的android版的三方库,现在把使用心得以及过程进行分享~

话不多说,搞起!

第一步:导包和权限

权限:

   
    
    
    
    

这里多说一句,我用的是api导包方式(一个小知识点):

api("com.journeyapps:zxing-android-embedded:3.6.0") {
    exclude group: 'com.android.support'
}

肯定有朋友问了,为什么不用最常见的 implementation方式呢,好说,上面这种导入方式好处是,不会导致三方库的依赖包和项目本地的依赖包产生冲突,例如:com.android.support:appcompat-v7:28.0.0-beta01包,所以我建议各位以后导库都用上面的方式,一劳永逸,没懂?无所谓跟着做肯定没毛病,当然前提你的AS版本 >= 3.0的,要不然当我没说。

第二步:创建自定义ViewfinderView 类:

新建一个类 MyViewFinderView 继承 ViewfinderView 类,并重写它的两个方法:onDraw(Canvas canvas) 和 refreshSizes()方法。

onDraw(Canvas canvas) 里的内容去源码中copy即可,下面是我自己改的自定义样式代码:

    @Override
    public void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        refreshSizes();
        if (framingRect == null || previewFramingRect == null) {
            return;
        }

        final Rect frame = framingRect;
        final Rect previewFrame = previewFramingRect;

        final int width = canvas.getWidth();
        final int height = canvas.getHeight();

        // 注意此处如果不进行赋值,就会走下面的else方法,绘制图形。我比较懒,就直接引入了一个扫描边框图片。
        resultBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.sc_bg);
        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);

        // 此处是我自己写绘制的扫描线
        drawScLine(liney, canvas);

        if (resultBitmap != null) {
            // Draw the opaque result bitmap over the scanning rectangle
            paint.setAlpha(CURRENT_POINT_OPACITY);
            canvas.drawBitmap(resultBitmap, null, frame, paint);
        } else {

            // 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;
            final int middle = frame.height() / 2 + frame.top;
            canvas.drawRect(frame.left + 2, middle - 1, frame.right - 1, middle + 2, paint);

            final float scaleX = frame.width() / (float) previewFrame.width();
            final float scaleY = frame.height() / (float) previewFrame.height();

            final int frameLeft = frame.left;
            final int frameTop = frame.top;

            // draw the last possible result points
            if (!lastPossibleResultPoints.isEmpty()) {
                paint.setAlpha(CURRENT_POINT_OPACITY / 2);
                paint.setColor(resultPointColor);
                float radius = POINT_SIZE / 2.0f;
                for (final ResultPoint point : lastPossibleResultPoints) {
                    canvas.drawCircle(
                            frameLeft + (int) (point.getX() * scaleX),
                            frameTop + (int) (point.getY() * scaleY),
                            radius, paint
                    );
                }
                lastPossibleResultPoints.clear();
            }

            // draw current possible result points
            if (!possibleResultPoints.isEmpty()) {
                paint.setAlpha(CURRENT_POINT_OPACITY);
                paint.setColor(resultPointColor);
                for (final ResultPoint point : possibleResultPoints) {
                    canvas.drawCircle(
                            frameLeft + (int) (point.getX() * scaleX),
                            frameTop + (int) (point.getY() * scaleY),
                            POINT_SIZE, paint
                    );
                }

                // swap and clear buffers
                final List temp = possibleResultPoints;
                possibleResultPoints = lastPossibleResultPoints;
                lastPossibleResultPoints = temp;
                possibleResultPoints.clear();
            }

            // Request another update at the animation interval, but only repaint the laser line,
            // not the entire viewfinder mask.
            postInvalidateDelayed(ANIMATION_DELAY,
                    frame.left - POINT_SIZE,
                    frame.top - POINT_SIZE,
                    frame.right + POINT_SIZE,
                    frame.bottom + POINT_SIZE);
        }

    }

refreshSizes()方法内容:

  @Override
    protected void refreshSizes() {
        if (cameraPreview == null) {
            return;
        }
        // 设置二维码扫描框大小,正常要自己适配屏幕大小,按照比例写的,我比较懒写死了,嘿嘿。
        framingRect = new Rect(165, 432, 915, 1182);//二维码框

        Rect previewFramingRect = cameraPreview.getPreviewFramingRect();
        if (framingRect != null && previewFramingRect != null) {
            this.framingRect = framingRect;
            this.previewFramingRect = previewFramingRect;
        }
    }

附赠我的扫描线绘制方法以及动画方法and启动动画逻辑:

初始化画笔:

   /**
     * 初始化画笔
     *
     * @param paintSize  画笔大小
     * @param paintColor 画笔颜色
     * @return
     */
    private Paint initPaint(int paintSize, int paintColor) {
        Paint paint = new Paint();
        //设置抗锯齿
        paint.setAntiAlias(true);
        //设置画笔笔尖样式
        paint.setStrokeCap(Paint.Cap.ROUND);
        //设置填充模式,默认为FILL
        paint.setStyle(Paint.Style.STROKE);
        //设置画笔大小
        paint.setStrokeWidth(paintSize);
        //设置颜色
        paint.setColor(getResources().getColor(paintColor));
        return paint;
    }

 

绘制扫描线:
 

 private void drawScLine(int y, Canvas canvas) {
        Paint paint = initPaint(8, R.color.colorAccent);
        Path line = new Path();
        int x = framingRect.left + framingRect.width() / 10 * 2;
        line.moveTo(x, y);
        line.lineTo(x + framingRect.width() / 10 * 6, y);
        canvas.drawPath(line, paint);
    }

扫描线扫描动作动画:

   private void startAnimator() {
        animator = ValueAnimator.ofInt(framingRect.top, framingRect.bottom);
        animator.setDuration(5000);
        animator.setRepeatCount(ValueAnimator.INFINITE);//无限循环
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                Integer value = (Integer) animation.getAnimatedValue();
                liney = value;
                Log.e("valuevaluevalue", value + "");
                myhandler.sendEmptyMessage(0);
            }
        });
        animator.start();
    }

为了照顾懒癌晚期患者,我handler都送给你:

    public static class Myhandler extends android.os.Handler {
        private WeakReference weakReference;
        private MyViewFinderView myViewFinderView;

        public Myhandler(MyViewFinderView myViewFinderView) {
            weakReference = new WeakReference<>(myViewFinderView);
        }

        @Override
        public void handleMessage(Message msg) {
            myViewFinderView = weakReference.get();
            myViewFinderView.invalidate();
        }
    }

在onWindowFocusChanged()方法中监听进行初始化handler和动画的启动操作:

    @Override
    public void onWindowFocusChanged(boolean hasWindowFocus) {
        super.onWindowFocusChanged(hasWindowFocus);
        if (hasWindowFocus) {
            myhandler = new Myhandler(this);
            if (firstLoad) {
                startAnimator();
                firstLoad = false;
            }
        }
    }

记得在onDetachedFromWindow()方法中结束动画,减少内存开销:


    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        if (animator != null) {
            animator.cancel();
        }
    }

第三步:布局xml更改:

在你要显示的扫描页的xml布局文件中引入我们的自定义控件:

   

整体myviewfinder.xml如下,懒癌患者直接copy即可:




    

    

    

第四步:创建扫描二维码页面

我比较懒,直接给你们代码了:

/**
 * 扫描二维码页面
 */
public class ScActivity extends AppCompatActivity {
    private CaptureManager captureManager;
    private DecoratedBarcodeView mDBV;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_sc);

        mDBV = findViewById(R.id.dbv_custom);

        //重要代码,初始化捕获
        captureManager = new CaptureManager(this, mDBV);
        captureManager.initializeFromIntent(getIntent(), savedInstanceState);
        captureManager.decode();
    }

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

    @Override
    protected void onPause() {
        super.onPause();
        captureManager.onPause();
    }


    @Override
    protected void onDestroy() {
        super.onDestroy();
        captureManager.onDestroy();
    }
}

页面的xml也给你们:




    
    

    

 

第五步:初始化并使用

初始化:

    private void initScan() {
        integrator = new IntentIntegrator(this);
        integrator.setPrompt("请扫描二维码"); //底部的提示文字,设为""可以置空
        integrator.setCameraId(0); //前置或者后置摄像头
        integrator.setBeepEnabled(true); //扫描成功的「哔哔」声,默认开启
        integrator.setCaptureActivity(ScActivity.class); //设置扫描activity
    }

调用:

integrator.initiateScan();

搞定收工~

最后几句:我是把自定义和使用合到一起写了,因为我比较懒嘛~按照我这个步骤就就可以使用,粗心大意的多检查检查就行了,我这几乎都是把源码贴上来了,所以就不发源码了。(就这点东西还用得着源码?小声嘀咕)

你可能感兴趣的:(二维码)