Android二维码开发(三)封装

[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下载

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,590评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,808评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,151评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,779评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,773评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,656评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,022评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,678评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,038评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,756评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,411评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,005评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,973评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,053评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,495评论 2 343

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,435评论 25 707
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,019评论 4 62
  • 周五下午,暖暖的阳光驱散了连续的阴雨天。我带孩子们出去玩,播放音乐用的u盘插在小蜜蜂上。闲转的时候,u盘的接口...
    一抹茶色z阅读 572评论 3 4
  • 按需要定制MapReduc map和reduce可以用自己编程 目标在于多次的目标流读区,而不是读写 hdfs存储...
    jose_dl阅读 135评论 0 0
  • 横看成岭侧成峰,远近高低各不同,不识庐山真面目,只缘身在此山中。 我是个搞技术的IT男、程序猿,也算是半拉产品经理...
    popeye0523阅读 314评论 0 0