前言

微信的二维码扫描用的越来越多,所以最近就想弄明白它的实现,于是找了点资料,发现都是说使用zxing的开源库。这是一个很强大的开源项目,引用该项目只要简单的几步代码就能实现一个简单的二维码扫描与生成的效果。这里做点笔记记下,还不知道如何实现的也可以来学习下。

准备工作

先下载zxing项目,不过推荐下载精简版,BarCodeTest这个就足够实现该功能了。把下载的项目添加到自己项目的依赖中,引用该项目。如何添加Module这里就不多说了相信大家都能自己解决。下面进行实现操作。

扫描二维码

因为是引用别人的开源项目,所以我们能很简单的使用别人定义好的类来实现该功能,这里用到的主要是CaptureActivit类,当我们要扫描时跳转到该类开启扫描功能:

//打开扫描界面扫描条形码或二维码
Intent openCameraIntent = new Intent(BarCodeTestActivity.this,CaptureActivity.class);
                startActivityForResult(openCameraIntent, 0);

重写onActivityResult方法,通过TextView显示出扫描的结果:

@Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        //处理扫描结果(在界面上显示)
        if (resultCode == RESULT_OK) {
            Bundle bundle = data.getExtras();
            String scanResult = bundle.getString("result");
            resultTextView.setText(scanResult);
        }
    }

这里直接通过bundle.getString("result")就可以获取扫描的结果,因为在CaptureActivity中的handleDecode已经对其做了处理:

public void handleDecode(Result result, Bitmap barcode) {
        inactivityTimer.onActivity();
        playBeepSoundAndVibrate();
        String resultString = result.getText();
        //FIXME
        if (resultString.equals("")) {
            Toast.makeText(CaptureActivity.this, "Scan failed!", Toast.LENGTH_SHORT).show();
        }else {
//            System.out.println("Result:"+resultString);
            Intent resultIntent = new Intent();
            Bundle bundle = new Bundle();
            bundle.putString("result", resultString);
            resultIntent.putExtras(bundle);
            this.setResult(RESULT_OK, resultIntent);
        }
        CaptureActivity.this.finish();
    }
扫描的功能到这里就结束了

生成二维码

这里生成二维码也很简单,只是要调用该开源项目的EncodingHandlercreateQRCode方法生成Bitmap对象,通过ImageView显示出来:

try {
                    String contentString = qrStrEditText.getText().toString();
                    if (!contentString.equals("")) {
                        //根据字符串生成二维码图片并显示在界面上,第二个参数为图片的大小(450*450)
                        Bitmap qrCodeBitmap = EncodingHandler.createQRCode(contentString, 450);
                        qrImgImageView.setImageBitmap(qrCodeBitmap);
                    } else {
                        Toast.makeText(BarCodeTestActivity.this, "Text can not be empty", Toast.LENGTH_SHORT).show();
                    }
                } catch (WriterException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
是不是感觉太简单了,没错就是这么简单,其实刚开始了解的时候也惊呆了,不禁感叹开源真是牛叉啊!

界面修改

其实通过上面的实现你会发现功能是实现了,但界面真是看不过去了,感觉瞬间回到了解放前似得,有木有这种感觉。看多了微信的二维码扫描,一下看这么low我实在是看不惯。我们可以简单的做下修改。首先我们找到CameraManager类,在该类中我们主要是修改下扫描框的大小(原来的实在是感觉太小气了)把相应的参数改大点就可以了,下面是我自己修改的大小:

private static final int MIN_FRAME_WIDTH = 400;
private static final int MIN_FRAME_HEIGHT = 400;
private static final int MAX_FRAME_WIDTH = 600;
private static final int MAX_FRAME_HEIGHT = 600;

下面要该的就是添加跟微信一样的移动激光条、四个角的简单装饰与文字显示。我们要找到ViewfinderView类,在onDraw方法中做绘制的修改。首先把原来的描边的颜色改成灰色:

paint.setColor(Color.GRAY);
      canvas.drawRect(frame.left, frame.top, frame.right + 1, frame.top + 2, paint);
      canvas.drawRect(frame.left, frame.top + 2, frame.left + 2, frame.bottom - 1, paint);
      canvas.drawRect(frame.right - 1, frame.top, frame.right + 1, frame.bottom - 1, paint);
      canvas.drawRect(frame.left, frame.bottom - 1, frame.right + 1, frame.bottom + 1, paint);

默认为绿色,因为下面我们要画跟微信一样的绿色的四个角,颜色一样就有点不协调了。

//画扫描框的四个装饰角
      paint.setColor(FRAME_COLOR);
      canvas.drawRect(frame.left, frame.top, frame.left + FRAME_WIDTH, frame.top + FRAME_HEIGHT, paint);
      canvas.drawRect(frame.left, frame.top, frame.left + FRAME_HEIGHT, frame.top + FRAME_WIDTH, paint);
      canvas.drawRect(frame.right - FRAME_WIDTH, frame.top, frame.right, frame.top + FRAME_HEIGHT, paint);
      canvas.drawRect(frame.right - FRAME_HEIGHT, frame.top, frame.right, frame.top + FRAME_WIDTH, paint);
      canvas.drawRect(frame.right - FRAME_HEIGHT, frame.bottom - FRAME_WIDTH, frame.right, frame.bottom, paint);
      canvas.drawRect(frame.right - FRAME_WIDTH, frame.bottom - FRAME_HEIGHT, frame.right, frame.bottom, paint);
      canvas.drawRect(frame.left,frame.bottom-FRAME_WIDTH,frame.left+FRAME_HEIGHT,frame.bottom,paint);
      canvas.drawRect(frame.left,frame.bottom-FRAME_HEIGHT,frame.left+FRAME_WIDTH,frame.bottom,paint);

这里主要的根据frametopleftrightbottom参数来绘制,每个角要绘制两次。FRAME_HEIGHTFRAME_WIDTH分别为自己设置的角的宽高。可以拿微信的对照。
下面修改激光线,把原来的激光绘制去掉添加如下代码:

//初始化laser
      if (!isStart){
        isStart = true;
        laserTop = frame.top;
        laserBottom = frame.bottom;
      }
//绘制laser
      laserTop += LASER_SPEED;//每次的移动距离
      if (laserTop >= frame.bottom){
        laserTop = frame.top;
      }
      canvas.drawRect(frame.left + LASER_WIDTH, laserTop - LASER_WIDTH / 2, frame.right - LASER_WIDTH, laserTop + LASER_WIDTH / 2, paint);
      //更新laser实现移动
      postInvalidateDelayed(ANIMATION_DELAY, frame.left, frame.top, frame.right, frame.bottom);

至于文字的绘制也是响应的原理,找到要绘制的坐标,调用canvas.drawText就可以了,不过画笔paint.setTextSize()单位是px(像素),这点感觉有点麻烦,在不同的分辨率的机型下字体的大小会相差很大。。有点蛋疼。希望有好的解决的方法可以告诉我。

效果图

文字我没有调,自己可以调下。我是按我手机居中来调的,这个是768 x 1280的,文字完全变样了。。。
图片描述

其他分享:https://idisfkj.github.io/

关注

clipboard.png


午后一小憩
2.9k 声望838 粉丝