一、关于ZXing

现在一维码二维码在我们的日常生活中使用如此的广泛,所以拥有扫码功能的APP变得非常普遍,一个安卓APP需要扫码功能就要用到zxing了,zxing是谷歌开源的让开发者更方便使用摄像头的库,而我们常用的扫码功能就是其中之一。

github地址:https://github.com/zxing/zxing

但是因为zxing的功能太强大了,包含了很多我们用不上的功能,所以一般都会抽取其中的扫码功能单独使用,这个抽取的过程还是有点麻烦的,但是已经有很多开发者为我们省去了这个过程,现在就来介绍一个很棒的第三方zxing库:zxing-android-embedded

二、第三方zxing库zxing-android-embedded

github地址:https://github.com/journeyapps/zxing-android-embedded

使用方式也很简单,首先在gradle中添加依赖

compile 'com.journeyapps:zxing-android-embedded:3.5.0'

然后在Activity或fragment中调用即可:

new IntentIntegrator(this).setDesiredBarcodeFormats(IntentIntegrator.ONE_D_CODE_TYPES)// 扫码的类型,可选:一维码,二维码,一/二维码.setPrompt("请对准二维码")// 设置提示语.setCameraId(0)// 选择摄像头,可使用前置或者后置.setBeepEnabled(false)// 是否开启声音,扫完码之后会"哔"的一声.setBarcodeImageEnabled(true)// 扫完码之后生成二维码的图片.initiateScan();// 初始化扫码

扫完码之后会在onActivityResult方法中回调结果

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {IntentResult result = IntentIntegrator.parseActivityResult(requestCode, resultCode, data);if(result != null) {if(result.getContents() == null) {Toast.makeText(this, "Cancelled", Toast.LENGTH_LONG).show();} else {Toast.makeText(this, "Scanned: " + result.getContents(), Toast.LENGTH_LONG).show();}} else {super.onActivityResult(requestCode, resultCode, data);}
}

以上就是简单的使用方式了

三、自定义界面

我们开发的时候可能会想要自定义界面,那么就需要我们修改代码了,自定义界面可以实现的:
1. 默认的的扫码是横屏的,自定义后可以竖屏扫码
2. 修改扫码框布局,可以添加其他View

其实在设置IntentIntegrator时会有一个方法:setCaptureActivity(Activity),这个方法就是用来设置扫码界面的Activity,当不设置的时候会默认调用库作者自己写的CaptureActivity,我们可以一起看一下这个Activity里面做了什么:

public class CaptureActivity extends Activity {private CaptureManager capture;private DecoratedBarcodeView barcodeScannerView;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);barcodeScannerView = initializeContent();capture = new CaptureManager(this, barcodeScannerView);capture.initializeFromIntent(getIntent(), savedInstanceState);capture.decode();}...省略代码
}

这里有2个很重要的成员变量:CaptureManager和DecoratedBarcodeView,从他们的名字可以看出:
1. CaptureManager是用来拉起扫码和处理扫码结果的类
2. DecoratedBarcodeView则是一个显示扫码界面的自定义View

有了这个了解之后我们要自定义扫码界面就很明了了,再一起简单看一下DecoratedBarcodeView是个啥:

public class DecoratedBarcodeView extends FrameLayout {private BarcodeView barcodeView;private ViewfinderView viewFinder;private TextView statusView;...省略代码
}
  1. BarcodeView就是背景
  2. ViewfinderView就是扫描框
  3. TextView为下方提示文字

上个图:

了解了这三个View的作用之后我们就可以开始我们的自定义了,而这三个View具体怎么去扫码与解析并不是我们关心的重点我们直接跳过。自定义界面的步骤:

  1. 新建一个Activity
  2. 把CaptureManager和DecoratedBarcodeView复制到我们自定义的Activity中
  3. 设置setCaptureActivity(CustomCaptureActivity.class)为我们自己的Activity
  4. 别忘了把自定义的Activity加入到AndroidManifest.xml中注册

上代码,我自定义的activity:

public class CustomCaptureActivity extends Activity {private CaptureManager capture;private DecoratedBarcodeView barcodeScannerView;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_custom_capture);// 自定义布局barcodeScannerView = (DecoratedBarcodeView) findViewById(R.id.dbv_custom);capture = new CaptureManager(this, barcodeScannerView);capture.initializeFromIntent(getIntent(), savedInstanceState);capture.decode();}@Overrideprotected void onResume() {super.onResume();capture.onResume();}@Overrideprotected void onPause() {super.onPause();capture.onPause();}@Overrideprotected void onDestroy() {super.onDestroy();capture.onDestroy();}@Overrideprotected void onSaveInstanceState(Bundle outState) {super.onSaveInstanceState(outState);capture.onSaveInstanceState(outState);}@Overridepublic void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], @NonNull int[] grantResults) {capture.onRequestPermissionsResult(requestCode, permissions, grantResults);}@Overridepublic boolean onKeyDown(int keyCode, KeyEvent event) {return barcodeScannerView.onKeyDown(keyCode, event) || super.onKeyDown(keyCode, event);}
}

自定义的布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"android:layout_width="match_parent"android:layout_height="match_parent"android:gravity="center_horizontal"android:orientation="vertical"><com.journeyapps.barcodescanner.DecoratedBarcodeView        android:id="@+id/dbv_custom"android:layout_width="match_parent"android:layout_height="235dp"android:layout_marginLeft="20dp"android:layout_marginRight="20dp"android:layout_marginTop="50dp"app:zxing_preview_scaling_strategy="fitXY" /><Button        android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="30dp"android:text="我是新添加的按钮啊" /></LinearLayout>

调用方式:

new IntentIntegrator(this)// 自定义Activity,重点是这行----------------------------.setCaptureActivity(CustomCaptureActivity.class).setDesiredBarcodeFormats(IntentIntegrator.ONE_D_CODE_TYPES)// 扫码的类型,可选:一维码,二维码,一/二维码.setPrompt("请对准二维码")// 设置提示语.setCameraId(0)// 选择摄像头,可使用前置或者后置.setBeepEnabled(false)// 是否开启声音,扫完码之后会"哔"的一声.setBarcodeImageEnabled(true)// 扫完码之后生成二维码的图片.initiateScan();// 初始化扫码

这是我修改过后的界面:

大家可以根据自己的需要定制自己想要的界面。

四、扫码后不结束扫码界面Activity

我们在使用zxing-android-embedded时会发现一点,那就是每次扫完码之后都会结束掉扫码界面Activity,然后在上一个Activity的onActivityResult获取扫码的结果,一般情况下这样的操作是可以满足我们项目中的需求,但是作者最近在开发的时候遇到了一个需求,需要在扫完码之后在不退出Activity的情况下弹出一个Dialog,然后在Dialog消失之后再扫码。找了一圈发现zxing-android-embedded没有提供这样的方法可以满足扫码后不结束扫码Activity。没办法逼得我去查阅源码看能否从源码下手,这里总结一下需求:
1. 首先扫码结束后不能结束扫码Activity
2. 在扫码Activity中能获取到扫码的结果
3. 获取到结果之后弹出Dialog,此时扫码应该是处于暂停状态,否则会出现未知问题
4. Dialog消失之后应该重新激活扫码

有了以上的需求,我们就从调用扫码的地方开始看起:

new IntentIntegrator(this).setCaptureActivity(CustomCaptureActivity.class)// 自定义Activity.setDesiredBarcodeFormats(IntentIntegrator.ONE_D_CODE_TYPES)// 扫码的类型,可选:一维码,二维码,一/二维码.setPrompt("请对准二维码")// 设置提示语.setCameraId(0)// 选择摄像头,可使用前置或者后置.setBeepEnabled(false)// 是否开启声音,扫完码之后会"哔"的一声.setBarcodeImageEnabled(true)// 扫完码之后生成二维码的图片.initiateScan();// 初始化扫码

构造方法中把当前的Activity设置到IntentIntegrator中,作者demo中对应的是MainActivity

public IntentIntegrator(Activity activity) {this.activity = activity;
}

然后关键的第二行,设置扫码Activity

public IntentIntegrator setCaptureActivity(Class<?> captureActivity) {this.captureActivity = captureActivity;return this;
}

从第三行开始就是对一些属性的设置了,这些不是我们关心的重点,所以我们跳过。说了这么久还没有提到过IntentIntegrator这个类,这个类其实是我们调用扫码的一个入口,各种参数都是在这个类中设置,还记得我们的需求是扫完码之后不结束扫码的Activity码?我们把重心放到captureActivity上,但是结果却是让人失落的,这个类中并没有captureActivity相关的操作,不过在initiateScan()方法中我们可以找到一些蛛丝马迹。

public final void initiateScan() {startActivityForResult(createScanIntent(), REQUEST_CODE);
}

这里只有简单的一行代码,让我们先看一下createScanIntent()中做了什么:

public Intent createScanIntent() {Intent intentScan = new Intent(activity, getCaptureActivity());intentScan.setAction(Intents.Scan.ACTION);// check which types of codes to scan forif (desiredBarcodeFormats != null) {// set the desired barcode typesStringBuilder joinedByComma = new StringBuilder();for (String format : desiredBarcodeFormats) {if (joinedByComma.length() > 0) {joinedByComma.append(',');}joinedByComma.append(format);}intentScan.putExtra(Intents.Scan.FORMATS, joinedByComma.toString());}intentScan.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);intentScan.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);attachMoreExtras(intentScan);return intentScan;
}

这段代码我们只需要关心第一行即可,从第一行我们可以知道这个方法会返回一个Intent,这个Intent就是从activity跳转到我们自定义的captureActivity,并且携带了很多设置的参数,让我返回到startActivityForResult()中:

protected void startActivityForResult(Intent intent, int code) {if (fragment != null) {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {fragment.startActivityForResult(intent, code);}} else if (supportFragment != null) {supportFragment.startActivityForResult(intent, code);} else {activity.startActivityForResult(intent, code);}
}

因为我们的扫码有可能是从fragment中调用的,所以框架的作者在这里分别做了对fragment和activity中调用扫码的处理,这里我们关心activity即可,很可惜,IntentIntegrator中没有我们能下手的地方,但是我们了解到扫码的操作其实都是在captureActivity做的,让我们把重点放到captureActivity中。

其实在第三节中我们我们已经看过这个Activity了,但是我们当时只关心自定义界面,所以忽略了一个重要的类:CaptureManager,这个类其实就是真正处理扫码的地方,所有的设置、界面、Activity的调用都会在CaptureManager完成,我们先看一下他的使用:

capture = new CaptureManager(this, barcodeScannerView);
capture.initializeFromIntent(getIntent(), savedInstanceState);
capture.decode();

构造方法中会把当前扫码Activity和扫码的View设置进去。

public CaptureManager(Activity activity, DecoratedBarcodeView barcodeView) {this.activity = activity;this.barcodeView = barcodeView;barcodeView.getBarcodeView().addStateListener(stateListener);handler = new Handler();inactivityTimer = new InactivityTimer(activity, new Runnable() {@Overridepublic void run() {Log.d(TAG, "Finishing due to inactivity");finish();}});beepManager = new BeepManager(activity);
}

而initializeFromIntent()方法主要是从Intent中取出我们所设置的各种扫码的参数,这里就不给出源码了。

/*** Start decoding.*/
public void decode() {barcodeView.decodeSingle(callback);
}

最后的decode()方法就是真正开始扫码的地方,我们可以看到这里barcodeView调用了decodeSingle方法开启扫码,还设置了一个回调进去,可以猜到这个callback就是用来接收扫码结果的回调了

private BarcodeCallback callback = new BarcodeCallback() {@Overridepublic void barcodeResult(final BarcodeResult result) {barcodeView.pause();beepManager.playBeepSoundAndVibrate();handler.post(new Runnable() {@Overridepublic void run() {returnResult(result);}});}@Overridepublic void possibleResultPoints(List<ResultPoint> resultPoints) {}
};

在这个回调中看到一个returnResult(result),这个就是扫码之后返回结果的地方了,我们果然没有猜错

protected void returnResult(BarcodeResult rawResult) {Intent intent = resultIntent(rawResult, getBarcodeImagePath(rawResult));activity.setResult(Activity.RESULT_OK, intent);closeAndFinish();
}

BarcodeResult就是我们的扫码结果了,第一行代码用来解析BarcodeResult并生成一个Intent,这个Intent就是用来携带扫码结果返回到onActivityResult的关键了,第三行代码的名字很明显就是用来结束Activity的方法了吧,跟进去看:

protected void closeAndFinish() {if(barcodeView.getBarcodeView().isCameraClosed()) {finish();} else {finishWhenClosed = true;}barcodeView.pause();inactivityTimer.cancel();
}
private void finish() {activity.finish();
}

罪魁祸首就是这个finish()方法了!!就是它,它把我们的Activity结束掉了,找到源头了就可以下手了。我们把它给注释掉就结束不了我们的Activity了。但是现在Activity不结束了,但是我们要把结果给返回回去啊,那我们自己得加个回调了

public interface ResultCallBack {void callBack(int requestCode, int resultCode, Intent intent)
}private ResultCallBack mResultCallBack;public void setResultCallBack(ResultCallBack resultCallBack) {this.mResultCallBack = resultCallBack;
}

修改后的returnResult方法为下,这里我修改的是returnResult方法,而并没有修改上面的closeAndFinish方法,因为closeAndFinish方法不只是在返回扫码结构的时候调用了,所以为了防止出问题就修改是returnResult方法

/*** 修改此方法,实现扫码之后不返回界面*/
protected void returnResult(BarcodeResult rawResult) {Intent intent = resultIntent(rawResult, getBarcodeImagePath(rawResult));activity.setResult(Activity.RESULT_OK, intent);if (barcodeView.getBarcodeView().isCameraClosed()) {if (null != mResultCallBack) {mResultCallBack.callBack(IntentIntegrator.REQUEST_CODE, Activity.RESULT_OK, intent);}// activity.finish(); 注释掉这行} else {finishWhenClosed = true;}barcodeView.pause();inactivityTimer.cancel();
}

到这里为止我们的修改就完了,其实改动非常小,就几行代码就可以实现扫完码之后不结束扫码Activity,但是重要的是思考的过程和阅读源码的过程,刚拿到那些需求然后发现第三方库实现不了的时候我也是非常慌的,也尝试过修改源码但是没有成功,最后一次静下心来慢慢翻看源码终于搞定了,这也是对我自己的一次提升吧,谢谢大家阅读文章,最后附上修改后的代码:

修改后的CustomCaptureActivity:

public class CustomCaptureActivity extends Activity {private CaptureManager capture;private DecoratedBarcodeView barcodeScannerView;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_custom_capture);// 自定义布局barcodeScannerView = (DecoratedBarcodeView) findViewById(R.id.dbv_custom);capture = new CaptureManager(this, barcodeScannerView);capture.initializeFromIntent(getIntent(), savedInstanceState);capture.setResultCallBack(new CaptureManager.ResultCallBack() {@Overridepublic void callBack(int requestCode, int resultCode, Intent intent) {IntentResult result = IntentIntegrator.parseActivityResult(requestCode, resultCode, intent);if (null != result && null != result.getContents()) {showDialog(result.getContents());}}});capture.decode();}public void showDialog(String result) {// 弹出dialog的代码略...// 重新拉起扫描capture.onResume();capture.decode();}@Overrideprotected void onResume() {super.onResume();capture.onResume();}@Overrideprotected void onPause() {super.onPause();capture.onPause();}@Overrideprotected void onDestroy() {super.onDestroy();capture.onDestroy();}@Overrideprotected void onSaveInstanceState(Bundle outState) {super.onSaveInstanceState(outState);capture.onSaveInstanceState(outState);}@Overridepublic void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], @NonNull int[] grantResults) {capture.onRequestPermissionsResult(requestCode, permissions, grantResults);}@Overridepublic boolean onKeyDown(int keyCode, KeyEvent event) {return barcodeScannerView.onKeyDown(keyCode, event) || super.onKeyDown(keyCode, event);}
}

修改后的CaptureManager:

public class CaptureManager{... 省略代码/*** 修改此方法,实现扫码之后不返回界面**@author mark.liu* created at 2017-9-5*/protected void returnResult(BarcodeResult rawResult) {Intent intent = resultIntent(rawResult, getBarcodeImagePath(rawResult));activity.setResult(Activity.RESULT_OK, intent);if (barcodeView.getBarcodeView().isCameraClosed()) {if (null != mResultCallBack) {mResultCallBack.callBack(IntentIntegrator.REQUEST_CODE, Activity.RESULT_OK, intent);}// activity.finish(); 注释这一行} else {finishWhenClosed = true;}barcodeView.pause();inactivityTimer.cancel();}public interface ResultCallBack {void callBack(int requestCode, int resultCode, Intent intent);}private ResultCallBack mResultCallBack;public void setResultCallBack(ResultCallBack resultCallBack) {this.mResultCallBack = resultCallBack;}... 省略代码
}

第三方ZXing库zxing-android-embedded使用及自定义相关推荐

  1. 【Android NDK 开发】NDK 交叉编译 ( Ubuntu 中交叉编译动态库 | Android Studio 中配置使用第三方动态库 )

    文章目录 I . 动态库 与 静态库 II . 编译动态库 III. Android Studio 使用第三方动态库 IV . Android Studio 关键代码 V . 博客资源 I . 动态库 ...

  2. Android Studio使用zxing库扫描并解析条形码

    首先导入zxing库,打开app下的build.gradle位置如下. 打开后在如下位置后,在dependencies中 添加划线的那行代码,即: compile 'com.journeyapps:z ...

  3. zxing android 自定义,ZXing Android Embedded 的使用以及自定义布局 · 小憩之地

    8种机械键盘轴体对比 本人程序员,要买一个写代码的键盘,请问红轴和茶轴怎么选? 想做个扫描条形码的功能,第一想到的就是 ZXing 了.ZXing 的功能很强大,通常不需要完整把整个库都作为依赖放进应 ...

  4. Android开发--Zxing库实现二维码/条形码扫描识别

    首先要下载所需要的源码,可以从zxing官网下载,下载压缩包然后解压到自己要放的地址 然后导入zxing包,下载的zxing源码中我们能用到的大概就camera,decoding,view三个包,可直 ...

  5. Android常用的第三方开源库和框架

    第三方开源库和组件 一个专注于平滑滚动的Android图像加载和缓存库 https://github.com/bumptech/glide 图片缓存Universal-Image-Loader: ht ...

  6. 二维码扫描开源库ZXing定制化【转】

    转自:http://www.cnblogs.com/sickworm/p/4562081.html 最近在用ZXing这个开源库做二维码的扫描模块,开发过程的一些代码修改和裁剪的经验和大家分享一下. ...

  7. 生成和扫描二维码(ZXing库)

    生成和扫描二维码(ZXing库) 一.ZXing概述 ZXing是谷歌自己推出的一个开源源码的二维码框架,可以实现使用手机的摄像头完成条形码的扫描和解码. 二.整合ZXing框架 将预先获取的core ...

  8. Android:实际运用Zxing集成二维码扫描 及 自定义扫码界面(demo源码)

    二维码扫描,各大主流App必不可少的功能,而且google已将轮子替我们造好,直接拿来使用即可.以下是教学如何将Zxing开源库集成到自己项目中,并且自定义扫码界面,后期可根据自己的业务需求进行修改, ...

  9. 加载google Z-Xing库实现二维码解析与生成,并将解析结果在另一页面显示

    1.首先需要下载Z-Xing 库项目下载文档,可在http://download.csdn.net/detail/catchingsun/8903065进行下载: 2.解析二维码,并跳转至新建Acti ...

最新文章

  1. 手机怎么访问kodi_Kodi播放器
  2. Android的沉浸式状态栏与变色状态栏详解
  3. 神经网络模拟条件反射
  4. Android应用权限管理总结
  5. 【Keil C51】使用 watch1 来查看变量的值
  6. 【最简便解法】1069 微博转发抽奖 (20分)
  7. WF4 AttachedPropertiesService
  8. 泡泡玛特2021年营收44.9亿元 同比增长78.7%
  9. MAX脚本发送贴图的另外一个方式
  10. numpy array和python list_Python list与NumPy array 区分详解
  11. 大数据Hadoop原理:大数据Hadoop技术原理简介
  12. 呼和浩特市啥时计算机考试,2021上半年内蒙古自治区呼和浩特市全国计算机等级考试时间...
  13. 从零开始学java第一章 认识java
  14. NHibernate Step by Step (三) Configuration和Sessionfactory
  15. 一度智信:电商平台商品定价策略
  16. 美团后端一二面c++
  17. 平面设计美学的意义是什么?
  18. c语言打印字符图案,用printf()打印简单字符图案.ppt
  19. Django:发送邮件
  20. MacBook Pro 2018款充电口不能用解决办法

热门文章

  1. 厉害!「标题党」文章都能用 Python 分析出来
  2. uAvionix获得FAA合同,部署和演示多个无人机同时飞行的C波段频率分配管理(FAM)
  3. 微软与网景关于浏览器的恩怨情仇
  4. 聚焦运营商信创运维,美信时代监控易四大亮点值得一试!
  5. zk4元年拆解_耐克ZK5 Protro 科五复刻“减配”?可能你根本不懂曼巴心意!
  6. HTTP协议详解1----请求状态与响应
  7. 百度平台上的网络舆情信息怎么搜查的方法
  8. C1-01基础任务和知识拓展
  9. Spring AOP之@Around,@AfterReturning使用、切不进去问题解决
  10. Python制作翻译工具(程序员必备中英文翻译工具)