美文网首页
Android二维码开发(三)封装

Android二维码开发(三)封装

作者: 好多个胖子 | 来源:发表于2017-07-13 14:39 被阅读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下载

    相关文章

      网友评论

          本文标题:Android二维码开发(三)封装

          本文链接:https://www.haomeiwen.com/subject/sdbwhxtx.html