Android二维码开发(三)封装

2017-07-13  本文已影响417人  好多个胖子

[TOC]

前言

接上篇,我们修改了扫码界面,不过整个库的方法调用还是比较繁琐,接下来对常用的扫码相关方法进行封装。

编写工具类

首先对生成二维码和识别图片二维码两个功能进行封装,代码不多直接贴出来,这其中生成二维码提供了加logo和不加logo两个方法供调用,详细看代码。

public class QRUtil {

    private static final int QR_BM_SIZE = 400;//生成二维码图片大小
    private static final int QR_BM_LOGO_SIZE = QR_BM_SIZE / 3;//logo大小


    public static Bitmap createQRBitmap(String context, int bm_size) {
        return createQRBitmap(context, bm_size, null, 2);
    }

    /**
     * 生成二维码
     *
     * @param context
     * @param bm_size
     * @param logo
     * @param edgeMargin
     * @return
     */
    public static Bitmap createQRBitmap(String context, int bm_size, Bitmap logo, int edgeMargin) {

        Bitmap bitmap = null;
        BitMatrix matrix = null;
        MultiFormatWriter writer = new MultiFormatWriter();
        try {
            //设置格式
            Map<EncodeHintType, Object> encodeHintTypeMap = new HashMap<>();
            encodeHintTypeMap.put(EncodeHintType.MARGIN, edgeMargin <= 0 ? 2 : edgeMargin);
            matrix = writer.encode(context, BarcodeFormat.QR_CODE, bm_size, bm_size, encodeHintTypeMap);

            BarcodeEncoder encoder = new BarcodeEncoder();
            bitmap = encoder.createBitmap(matrix);
            if (logo != null && !logo.isRecycled()) {
                bitmap = synthesisLogo(bitmap, logo);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return bitmap;
    }

    /**
     * 在二维码bitmap中加入logo
     * @param qrBm
     * @param logo
     * @return
     */
    private static Bitmap synthesisLogo(Bitmap qrBm, Bitmap logo) {
        Canvas canvas = new Canvas(qrBm);

        int w = logo.getWidth();
        int h = logo.getHeight();

        float wScale = QR_BM_LOGO_SIZE * 1.0f / w;
        float hScale = QR_BM_LOGO_SIZE * 1.0f / h;

        Matrix matrix = new Matrix();
        matrix.postScale(wScale, hScale);

        logo = Bitmap.createBitmap(logo, 0, 0, w, h, matrix, false);


        int middle = qrBm.getWidth() / 2;
        RectF rectF = new RectF(middle - QR_BM_LOGO_SIZE / 2, middle - QR_BM_LOGO_SIZE / 2, middle + QR_BM_LOGO_SIZE / 2, middle + QR_BM_LOGO_SIZE / 2);

        canvas.drawBitmap(logo, null, rectF, null);

        return qrBm;
    }


    /**
     * 识别bitmap中的二维码信息,该方法不宜在主线程调用
     *
     * @param bitmap
     * @return
     */
    public static Result spotQRCode(Bitmap bitmap) throws FormatException, ChecksumException, NotFoundException {
        Result result = null;
        int width = bitmap.getWidth();
        int height = bitmap.getHeight();
        int[] data = new int[width * height];

        bitmap.getPixels(data, 0, width, 0, 0, width, height);
        RGBLuminanceSource source = new RGBLuminanceSource(width, height, data);


        BinaryBitmap binaryBitmap = new BinaryBitmap(new HybridBinarizer(source));


        QRCodeReader reader = new QRCodeReader();
        //result中包含了扫描到的信息,调用 result.getText()可以获取到文本信息
        result = reader.decode(binaryBitmap);
        return result;
    }


}

封装扫码相关方法

封装之前需要考虑一下想要什么样的调用方式,一般我们希望通过一个方法启动,在一个监听类里面接收返回的数据就好,按照这样的思路我们新建一个类QRScannerHelper


 public class QRScannerHelper {

    private Activity mContext;
    private OnScannerCallBack mCallBack;


    public QRScannerHelper(Activity context) {
        this.mContext = context;
    }

    /**
     * 开启扫码界面
     */
    public void startScanner() {
        new IntentIntegrator(mContext)
                .setOrientationLocked(false)
                .setDesiredBarcodeFormats(IntentIntegrator.ALL_CODE_TYPES)
                .setPrompt("将二维码/条码放入框内,即可自动扫描")
                .initiateScan(); // 初始化扫描
    }

    /**
     * 设置扫码完成该的监听
     *
     * @param mCallBack
     */
    public void setCallBack(OnScannerCallBack mCallBack) {
        this.mCallBack = mCallBack;
    }

    /**
     * 该方法需要再activity的onActivityResult中调用获取返回的信息
     *
     * @param requestCode
     * @param resultCode
     * @param data
     */
    public void onActivityResult(int requestCode, int resultCode, Intent data) {

        IntentResult intentResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, data);
        if (mCallBack != null) {
            mCallBack.onScannerBack(intentResult.getContents());
        }
    }


    public interface OnScannerCallBack {
        void onScannerBack(String result);
    }
}

现在我们启动扫码的操作如下

 /**
     * 在onCreate中调用
     */
    private void initQRScanner() {
        mScannerHelper = new QRScannerHelper(this);
        mScannerHelper.setCallBack(new QRScannerHelper.OnScannerCallBack() {
            @Override
            public void onScannerBack(IntentResult result) {
                Toast.makeText(MainActivity.this, result.getContents(), Toast.LENGTH_SHORT).show();
            }
        });
    }
    
      @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (mScannerHelper != null) {
            mScannerHelper.onActivityResult(requestCode, resultCode, data);
        }
    }
    
        /**
     * 开启扫描界面
     *
     * @param view
     */
    public void start(View view) {
        mScannerHelper.startScanner();
    }
    
    

增加辅助功能 闪光灯开关和相册选取照片识别二维码

闪光灯开关

在zxing_capture.xml中增加2个按钮

<merge xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <!--
    This Activity is typically full-screen. Therefore we can safely use centerCrop scaling with
    a SurfaceView, without fear of weird artifacts. -->
    <com.journeyapps.barcodescanner.DecoratedBarcodeView
        android:id="@+id/zxing_barcode_scanner"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:zxing_framing_rect_height="200dp"
        app:zxing_framing_rect_width="200dp"
        app:zxing_preview_scaling_strategy="centerCrop"
        app:zxing_use_texture_view="false">


        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="bottom"
            android:layout_marginBottom="20dp"
            android:background="@android:color/transparent"
            android:gravity="center"
            android:orientation="horizontal">

            <!--切换闪光灯-->
            <ImageView
                android:id="@+id/btn_switch_light"
                android:layout_width="30dp"
                android:layout_height="30dp"
                android:src="@drawable/lights" />

            <!--打开相册-->
            <ImageView
                android:id="@+id/btn_open_album"
                android:layout_width="30dp"
                android:layout_height="30dp"
                android:layout_marginLeft="20dp"
                android:src="@drawable/pic" />

        </LinearLayout>
    </com.journeyapps.barcodescanner.DecoratedBarcodeView>

</merge>

DecoratedBarcodeView类其实已经封装好了打开和关闭闪光灯的方法,因此只需要在CaptureActivity调用

 mBarcodeScannerView.setTorchListener(this);
        mSwitchLightView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (isLightOn) {
                    mBarcodeScannerView.setTorchOff();
                } else {
                    mBarcodeScannerView.setTorchOn();
                }
            }
        });

相册选取照片分为相册选取照片加载到内存bitmap和对bitmap进行时和别操作,为了不在CaptureActivity引入过多的代码,我新建一个类将这部分代码进行封装,创建一个类叫QRSpotHelper,QRSpotHelper的详细代码较多不贴出来,可下载demo查看。在CaptureActivity中使用

    //相册选取按钮的点击事件
        mOpenAlbumView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (mQrSpotHelper == null) {
                    mQrSpotHelper = new QRSpotHelper(CaptureActivity.this, mOnSpotCallBack);
                }
                mQrSpotHelper.spotFromAlbum();
            }
        });
        
    //由于照片选取需要在onActivityResult中回调,因此需要添加下面代码
     @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (mQrSpotHelper != null) {
            mQrSpotHelper.onActivityResult(requestCode, resultCode, data);
        }
    }

        
     //照片识别的监听
    private QRSpotHelper.OnSpotCallBack mOnSpotCallBack = new QRSpotHelper.OnSpotCallBack() {
        @Override
        public void onSpotStart() {
            mProgressBar.setVisibility(View.VISIBLE);
        }

        @Override
        public void onSpotSuccess(Result result) {
            //识别成功后将返回的结果传递给上层activity
            mProgressBar.setVisibility(View.GONE);
            String data = result.getText();
            Intent intent = new Intent();
            intent.putExtra("data", data);
            setResult(SPOT_SUCCESS, intent);
            finish();
        }

        @Override
        public void onSpotError() {
            mProgressBar.setVisibility(View.GONE);
            Toast.makeText(CaptureActivity.this, "未发现二维码", Toast.LENGTH_SHORT).show();
        }
    };
        
        

在相册选取照片识别成功的代码中,我们将结果提交给上层activity,而上层activity的onActivityResult已经被我们在QRScannerHelper中拦截,因此需要重新修改QRScannerHelper的onActivityResult方法处理识别结果返回给监听类

 public void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (mCallBack == null) return;
        String result;
        if (requestCode == IntentIntegrator.REQUEST_CODE && resultCode == CaptureActivity.SPOT_SUCCESS) {
            result = data.getStringExtra("data");
        } else {
            IntentResult intentResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, data);
            result = intentResult.getContents();
        }
        mCallBack.onScannerBack(result);
    }
zongjie.png

通过上面对源代码的梳理和修改,对二维码的操作变得简单了许多。demo中所涉及到的一些样式仅仅作为参考,可自行修改。如有不足之处还请指出,感谢。

demo下载

上一篇下一篇

猜你喜欢

热点阅读