#过年不停更#HarmonyOS - Zxing-Embedded的使用 原创 精华
春节不停更,此文正在参加「星光计划-春节更帖活动」
作者:庄茂裕
前言:
项目开发中有需要用到扫码识别的功能,这个功能在很多项目中都应该会使用到,于是找到了Zxing-Embedded的鸿蒙版,相信有安卓开发经验的同学都知道这个Zxing-Embedded框架,下面就开始使用
一、ZXing Embedded简介及使用方法
下载地址:https://gitee.com/baijuncheng-open-source/zxing-embedded
安装:
方案一:本地源集成,用户可自定义修改
1.复制zxing_embedded文件夹到project目录;
2.修改设置:在settings.Gradle文件下添加依赖项到这个模块,如下所示
include ':entry', ':zxing-ohos-embedded'
3.例如,我们需要修改build.Gradle文件的入口模块下添加依赖项:
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
testCompile'junit:junit:4.12'
implementation project('zxing-embeded')
}
方案二:线上HAR包集成(这种方便,不能修改jar包代码)
在本地项目的build.gradled 的 dependencies 下添加
implementation 'com.gitee.baijuncheng-open-source:Zxing-Embedded:1.0.0’
然后同步一下sync project whit Gradle files 成功后即安装完毕 (基本上大部分框架都是这样集成)
基本使用:
创建scanner.xml文件,如下
<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
xmlns:ohos="http://schemas.huawei.com/res/ohos"
xmlns:ech="http://schemas.huawei.com/res/ohos-auto"
ohos:height="match_parent"
ohos:width="match_parent"
ohos:orientation="vertical">
<com.google.zxing.journeyapps.barcodescanner.DecoratedBarcodeView
ohos:id="$+id:zxing_barcode_scanne"
ohos:height="match_parent"
ohos:width="match_parent"
ech:zxing_scanner_layout="$layout:custom_barcode_scanner"/>
</DirectionalLayout>
提醒:导入任何自定义文件或者第三方库的时候必须加
xmlns:ech="http://schemas.huawei.com/res/ohos-auto"
DecoratedBarcodeViewdde的属性简介:
参数 | 描述 |
---|---|
counterclockwise | 可选。规定应该逆时针还是顺时针绘图。False = 顺时针,true = 逆时针。 |
app:zxing_preview_scaling_strategy | 预览视图的缩放策略,使用centerCrop即可 |
app:zxing_use_texture_view | 是否使用纹理视图(黑色背景) |
创建 cusstom_barcode_scammer.xml文件
//BarcodeView提供相机预览功能和图片解码功能
<com.google.zxing.journeyapps.barcodescanner.BarcodeView
ohos:width="match_parent"
ohos:height="match_parent"
ohos:id="$+id:zxing_barcode_surface"
app:zxing_framing_rect_width="250vp"
app:zxing_framing_rect_height="50vp"/>``
//在BarcodeView视图之上,提供取景框,外部透明背景,扫描激光线
<com.google.zxing.journeyapps.barcodescanner.ViewfinderView
ohos:width="match_parent"
ohos:height="match_parent"
ohos:id="$+id:zxing_viewfinder_view"
app:zxing_possible_result_points="$color:zxing_custom_possible_result_points"
app:zxing_result_view="$color:zxing_custom_result_view"
app:zxing_viewfinder_laser="$color:zxing_custom_viewfinder_laser"
app:zxing_viewfinder_laser_visibility="false"
app:zxing_viewfinder_mask="$color:zxing_custom_viewfinder_mask"/>
创建 scannerAbility文件
public class ScannerAbility extends BaseAbility implements DecoratedBarcodeView.TorchListener, Observable, Component.ClickedListener {
//
private CaptureManager capture;
private DecoratedBarcodeView barcodeScannerView;
//闪光灯的
private DirectionalLayout switchFlashlightLayout;
private ViewfinderView viewfinderView;
private BarcodeView barcodeView;
@Override
protected void onStart(Intent intent) {
super.onStart(intent);
//初始化视图
super.setUIContent(ResourceTable.Layout_ability_scanner);
initView();
}
//初始化视图变量
private void initView(){
barcodeScannerView = (DecoratedBarcodeView) findComponentById(ResourceTable.Id_zxing_barcode_scanne);
barcodeScannerView.setTorchListener(this);
barcodeView = (BarcodeView) findComponentById(ResourceTable.Id_zxing_barcode_surface);
/*设置扫描框的宽高*/
barcodeView.setFramingRectSize(new Size(1000,1000));
switchFlashlightLayout= (DirectionalLayout) findComponentById(ResourceTable.Id_open_Flashlight);
switchFlashlightLayout.setClickedListener(this);
Image back = (Image)findComponentById(ResourceTable.Id_back_icon);
back.setClickedListener(this);
viewfinderView = (ViewfinderView) findComponentById(ResourceTable.Id_zxing_viewfinder_view);
capture = new CaptureManager(this, barcodeScannerView);
capture.initializeFromIntent(getIntent(), null);
capture.setShowMissingCameraPermissionDialog(false);
//设置
changeMaskColor(null);
changeLaserVisibility(false);
BusHelper.getINSTANCE().register("CameraPreviewStarted", this);
}
//改变背景颜色
public void changeMaskColor(Component view) {
int color = Color.argb(80, 0,0,0);
viewfinderView.setMaskColor(color);
}
public void changeLaserVisibility(boolean visible) {
viewfinderView.setLaserVisibility(visible);
}
//下面控制capture
@Override
protected void onActive() {
super.onActive();
capture.onResume();
}
@Override
protected void onInactive() {
super.onInactive();
capture.onPause();
}
@Override
public void onSaveAbilityState(PacMap outState) {
super.onSaveAbilityState(outState);
capture.onSaveInstanceState(outState);
}
@Override
public void onRestoreAbilityState(PacMap inState) {
super.onRestoreAbilityState(inState);
capture.initializeFromIntent(getIntent(), inState);
capture.setShowMissingCameraPermissionDialog(false);
capture.decode();
}
@Override
protected void onStop() {
super.onStop();
BusHelper.getINSTANCE().unRegister(this);
capture.onDestroy();
}
@Override
public void onRequestPermissionsFromUserResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsFromUserResult(requestCode, permissions, grantResults);
capture.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
//解码
@Override
public void onSubscribe(Object object) {
if (capture != null)
capture.decode();
}
}
扫码识别成功后会返回上个页面,扫码成功后的回调也会在 onAbilityResult里面返回。我这里用到RxBus.getDefault().send方法传递消息,是由于项目用了fraction来承载。
//扫描结果的回调
@Override
protected void onAbilityResult(int requestCode, int resultCode, Intent data) {
if (requestCode != CUSTOMIZED_REQUEST_CODE && requestCode != REQUEST_CODE) {
// This is important, otherwise the result will not be passed to the fragment
super.onAbilityResult(requestCode, resultCode, data);
return;
}
switch (requestCode) {
case REQUEST_CODE: {
IntentResult result = IntentIntegrator.parseAbilityResult(requestCode, resultCode, data);
if (result != null) {
String toast;
if (result.getContents() == null) {
toast = "Cancelled from fragment";
} else {
toast = "Scanned from fragment: " + result.getContents();
// At this point we may or may not have a reference to the activity
HashMap parame = new HashMap();
parame.put(Constants.EVENT_IN_SCANNER_RESULT,result.getContents());
RxBus.getDefault().send(parame, Constants.EVENT_IN_SCANNER_RESULT);
}
}
return;
}
default:
break;
}
}
效果下图:
自定义扫描界面
由于Zxing框架的给扫描视图不太符合需求,因此要修改扫描的样式:
需要自定义View(继承ViewfinderView),重写onDraw方法,然后替换掉这里的ViewfinderView。
因为R.layout.zxing_barcode_scanner是源码中的布局文件,无法直接修改,所以还要重写一份布局文件给DecoratedBarcodeView加载,代码如下:
public class CustomViewfinderView extends ViewfinderView {
/**
* 重绘时间间隔
*/
public static final long CUSTOME_ANIMATION_DELAY = 16;
/* ****************************************** 边角线相关属性 ************************************************/
/**
* "边角线长度/扫描边框长度"的占比 (比例越大,线越长)
*/
public float mLineRate = 0.1F;
/**
* 边角线厚度 (建议使用dp)
*/
public float mLineDepth = 4;
/**
* 边角线颜色
*/
public Color mLineColor = new Color(Color.getIntColor("#1EBB81"));
public CustomViewfinderView(Context context, AttrSet attrSet) {
super(context, attrSet);
}
@Override
public void onDraw(Component component, Canvas canvas) {
super.onDraw(component, canvas);
//刷新扫描框的尺寸
refreshSizes();
if (framingRect == null || cameraPreview.getPreviewFramingRect() == null) {
return;
}
//获取扫描框的位置
Rect frame = framingRect;
Rect previewFrame = cameraPreview.getPreviewFramingRect();
int width = canvas.getLocalClipBounds().getWidth();
int height = canvas.getLocalClipBounds().getHeight();
//绘制4个角
paint.setColor(mLineColor); // 定义画笔的颜色即4个角的颜色
//画左上角
canvas.drawRect(frame.left, frame.top, frame.left + frame.getWidth() * mLineRate, frame.top + mLineDepth, paint);
canvas.drawRect(frame.left, frame.top, frame.left + mLineDepth, frame.top + frame.getHeight() * mLineRate, paint);
//画右上角
canvas.drawRect(frame.right - frame.getWidth() * mLineRate, frame.top, frame.right, frame.top + mLineDepth, paint);
canvas.drawRect(frame.right - mLineDepth, frame.top, frame.right, frame.top + frame.getHeight() * mLineRate, paint);
//画左下角
canvas.drawRect(frame.left, frame.bottom - mLineDepth, frame.left + frame.getWidth() * mLineRate, frame.bottom, paint);
canvas.drawRect(frame.left, frame.bottom - frame.getHeight() * mLineRate, frame.left + mLineDepth, frame.bottom, paint);
//画右下角
canvas.drawRect(frame.right - frame.getWidth() * mLineRate, frame.bottom - mLineDepth, frame.right, frame.bottom, paint);
canvas.drawRect(frame.right - mLineDepth, frame.bottom - frame.getHeight() * mLineRate, frame.right, frame.bottom, paint);
// 绘制外部(即框架矩形外)变暗
Color color = new Color(resultBitmap != null ? resultColor : maskColor);
paint.setColor(color);
canvas.drawRect(0, 0, width, frame.top, paint);
canvas.drawRect(0, frame.top, frame.left, frame.bottom + 1, paint);
canvas.drawRect(frame.right + 1, frame.top, width, frame.bottom + 1, paint);
canvas.drawRect(0, frame.bottom + 1, width, height, paint);
}
}
}
代码简介:
(1)onDraw方法中的大部分代码Copy自ViewfinderView,笔者添加部分逻辑:是边角线的绘制。
(2)代码的核心是在onDraw方法的第5行代码:
Rect frame = framingRect;
这个矩阵记录了扫描框四个顶点的坐标,有了这个变量,各位可以发挥想象力自定义自己需要的扫描样式。
接下来,我们用CustomViewfinderView替换掉ViewfinderView(如下所示)
<com.google.zxing.journeyapps.barcodescanner.BarcodeView
ohos:width="match_parent"
ohos:height="match_parent"
ohos:id="$+id:zxing_barcode_surface"
app:zxing_framing_rect_width="250vp"
app:zxing_framing_rect_height="50vp"/>
//自定义的view
<com.sgcc.evs.phone.view.CustomViewfinderView
ohos:width="match_parent"
ohos:height="match_parent"
ohos:id="$+id:zxing_viewfinder_view"
app:zxing_possible_result_points="$color:zxing_custom_possible_result_points"
app:zxing_result_view="$color:zxing_custom_result_view"
app:zxing_viewfinder_laser="$color:zxing_custom_viewfinder_laser"
app:zxing_viewfinder_laser_visibility="false"
app:zxing_viewfinder_mask="$color:zxing_custom_viewfinder_mask"/>
最后,运行结果如下(如图所示):
总结
本文简述了zxing-Embeded的鸿蒙版使用,这个库由于现在没有人维护了,有些还需要修复的,闪光灯是用不了的,自定义的扫描样式本文只是提供了一些思路,还有其他的样式修改,也可根据自定义这种方式修改,后期会继续进一步分享优化此框架的问题,欢迎各位鸿蒙开发者一起讨论与研究,共勉。
更多原创内容请关注:中软国际 HarmonyOS 技术团队
入门到精通、技巧到案例,系统化分享HarmonyOS开发技术,欢迎投稿和订阅,让我们一起携手前行共建鸿蒙生态。
感谢大佬分享使用方法,也希望来个大佬维护一下