一、添加zxing引入依赖项
在build.gradle(module)中添加:
implementation 'com.google.zxing:core:3.4.1'
implementation 'com.journeyapps:zxing-android-embedded:4.2.0'
由于我们要使用摄像头资源,所以还要在AndroidManifest.xml 文件的 <manifest> 标签内添加下面三个权限:
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
第一个是 CAMERA 权限,用于允许应用程序访问设备的摄像头。第二个和第三个是对摄像头自动对焦的要求声明。通常情况下,第二个和第三个权限声明是作为使用摄像头权限的前提条件来添加的。
二、使用zxing框架
在需要进行扫描操作的Activity.java中导入资源包:
import com.google.zxing.integration.android.IntentIntegrator;
import com.google.zxing.integration.android.IntentResult;
然后在Activity.java中重写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) {
textview.setText("Cancelled");
} else {
//将扫描结果放到textview中
textview.setText(result.getContents());
}
} else {
super.onActivityResult(requestCode, resultCode, data);
}
}
textview只是把扫描的数据显示出来,如果有其它操作可以在这里实现。
接下来我们要实现打开摄像头扫描界面,一般情况下都是按键触发。所以我们可以在Activity.java视图中创建一个按钮并监听按钮的消息,在监听方法中实现打开扫描界面:
scanbtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
IntentIntegrator integrator = new IntentIntegrator(Activity.this);
integrator.setDesiredBarcodeFormats(IntentIntegrator.QR_CODE);
integrator.setPrompt("请对准二维码");
integrator.setCameraId(0);
integrator.setOrientationLocked(false);
integrator.setBeepEnabled(true);
integrator.setBarcodeImageEnabled(true);
integrator.initiateScan();
}
});
Activity是Activity.java当前的类名。现在IntentIntegrator等对象因为没有添加进来会报红,暂时不需要管,直接编译即可,在编译过程中会自动下载相关依赖包。编译完成后就可以实现扫描功能了。如果编译过程中下载失败,可以重新编译几次。如果下载都成功了还报错,需要同步一下工程,在执行编译即可。
三、自定义扫描界面
打开扫描后发现,跟经常见到的扫描不太一样,该框架默认的扫描是横向全屏扫描,我们在大多情况下需要竖屏扫描并且有一些类似“取消”、“开灯”等按键操作,所以我们需要自己定义扫描界面,下面我简单的写了一个带有取消扫描的界面并把扫描方式改为竖屏。
首先我们要了解到扫描的创建过程:
integrator.initiateScan();是打开扫描的开始,我们进入到该方法内发现该方法只有一句话:
public final void initiateScan() {
startActivityForResult(createScanIntent(), requestCode);
}
创建了一个扫描Intent,我们继续看一下是怎么创建的,获取的界面又是哪一个
public Intent createScanIntent() {
Intent intentScan = new Intent(activity, getCaptureActivity());
intentScan.setAction(Intents.Scan.ACTION);
// check which types of codes to scan for
if (desiredBarcodeFormats != null) {
// set the desired barcode types
StringBuilder 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 intentScan = new Intent(activity, getCaptureActivity()); 原来我们要跳转到的界面是getCaptureActivity()。一步一步深入进去,最终会来到CaptureActivity.java里,这就是扫描的活动页面。如果我们想实现自己定义的界面只要重写CaptureActivity类就可以。
在这里我直接创建了一个新的EmptyActivity,在布局xml里创建了一个DecoratedBarcodeView和一个按键:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".scanf_dev">
<com.journeyapps.barcodescanner.DecoratedBarcodeView
android:id="@+id/bv_barcode"
android:layout_width="420dp"
android:layout_height="530dp"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.555"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.497"
app:zxing_preview_scaling_strategy="centerCrop"
app:zxing_use_texture_view="false" />
<Button
android:id="@+id/button_scan_back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="53dp"
android:text="取消"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/bv_barcode" />
</androidx.constraintlayout.widget.ConstraintLayout>
然后把CaptureActivity.java 复制到新建的java文件里,然后只需要改动initializeContent()方法里的控件ID与xml布局文件一致即可。然后在创建添加的button监听事件实现取消返回上一个活动页面全部代码如下:
package com.example.uitest;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.View;
import android.widget.Button;
import com.journeyapps.barcodescanner.CaptureManager;
import com.journeyapps.barcodescanner.DecoratedBarcodeView;
public class scanf_dev extends AppCompatActivity {
private CaptureManager capture;
private DecoratedBarcodeView barcodeScannerView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
barcodeScannerView = initializeContent();
capture = new CaptureManager(this, barcodeScannerView);
capture.initializeFromIntent(getIntent(), savedInstanceState);
capture.decode();
Button btn = findViewById(R.id.button_scan_back);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(scanf_dev.this,AddDevice.class);
startActivity(intent);
}
});
}
/**
* Override to use a different layout.
*
* @return the DecoratedBarcodeView
*/
protected DecoratedBarcodeView initializeContent() {
setContentView(R.layout.activity_scanf_dev);
return (DecoratedBarcodeView)findViewById(R.id.bv_barcode);
}
@Override
protected void onResume() {
super.onResume();
capture.onResume();
}
@Override
protected void onPause() {
super.onPause();
capture.onPause();
}
@Override
protected void onDestroy() {
super.onDestroy();
capture.onDestroy();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
capture.onSaveInstanceState(outState);
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
capture.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
return barcodeScannerView.onKeyDown(keyCode, event) || super.onKeyDown(keyCode, event);
}
}
扫描界面就算是做完了,接下来就是引用。在IntentIntegrator类中提供 了引用自定义扫描界面的方法,setCaptureActivity(CustomView.class);我们只需要在扫描按钮的监听事件中添加该方法就可以把我们新建的界面替换成扫描界面,改完后是下面这样:
scanbtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
IntentIntegrator integrator = new IntentIntegrator(AddDevice.this);
integrator.setDesiredBarcodeFormats(IntentIntegrator.QR_CODE);
integrator.setPrompt("请对准二维码");
integrator.setCameraId(0);
integrator.setOrientationLocked(false);
integrator.setBeepEnabled(true);
integrator.setBarcodeImageEnabled(true);
integrator.setCaptureActivity(scanf_dev.class);
integrator.initiateScan();
}
});
现在就可以实现竖屏扫描并且带有取消按钮了。如果需要更多功能都可以在自定义的界面里完成。