Android中集成ZXing实现二维码扫描与界面定制
二维码扫描技术原理
在移动应用开发中,二维码扫描功能通过调用设备摄像头捕获图像,利用解码算法提取其中编码的文本信息。这一过程涉及图像采集、条码识别和数据解析三个核心环节。常见的实现方式是基于开源解码库构建封装组件,以简化集成流程。
使用ZXing Android Embedded实现扫码功能
推荐采用 zxing-android-embedded 库进行快速集成,该库基于Google ZXing项目封装,提供开箱即用的扫码能力,并支持多种条码格式。
添加依赖项
implementation 'com.journeyapps:zxing-android-embedded:3.6.0'
- 最低兼容API Level为9(Android 2.3+)
- 建议使用AppCompat主题并启用Java 8语言特性
基础功能实现
通过 IntentIntegrator 启动默认扫码界面:
findViewById(R.id.scan_button).setOnClickListener(v -> {
IntentIntegrator integrator = new IntentIntegrator(this);
integrator.setDesiredBarcodeFormats(IntentIntegrator.QR_CODE); // 仅识别二维码
integrator.setPrompt("将二维码放入框内自动扫描");
integrator.setBeepEnabled(true); // 扫描成功提示音
integrator.setOrientationLocked(false); // 允许屏幕旋转
integrator.initiateScan();
});
处理扫描结果
@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, "用户取消操作", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "结果:" + result.getContents(), Toast.LENGTH_LONG).show();
}
} else {
super.onActivityResult(requestCode, resultCode, data);
}
}
关键配置参数说明
| 方法 | 作用 |
|---|---|
setDesiredBarcodeFormats() |
指定识别类型,如 QR_CODE、CODE_128 等 |
setBeepEnabled() |
开启/关闭成功提示音 |
setCameraId() |
选择摄像头(0后置,1前置) |
setBarcodeImageEnabled() |
保存扫描到的图像至本地 |
setTimeout() |
设置超时自动退出时间(毫秒) |
强制竖屏显示配置
在 AndroidManifest.xml 中声明自定义 Activity 方向:
<activity
android:name="com.journeyapps.barcodescanner.CaptureActivity"
android:screenOrientation="portrait"
tools:replace="screenOrientation" />
自定义扫描界面
原生界面样式较为简陋,实际项目常需根据设计稿调整外观。可通过继承核心组件来自定义布局与动画效果。
创建自定义扫码Activity
public class CustomScannerActivity extends AppCompatActivity {
private CaptureManager captureManager;
private DecoratedBarcodeView barcodeView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_custom_scanner);
barcodeView = findViewById(R.id.barcode_scanner);
captureManager = new CaptureManager(this, barcodeView);
captureManager.initializeFromIntent(getIntent(), savedInstanceState);
captureManager.decode();
}
@Override
protected void onResume() {
super.onResume();
captureManager.onResume();
}
@Override
protected void onPause() {
super.onPause();
captureManager.onPause();
}
@Override
protected void onDestroy() {
super.onDestroy();
captureManager.onDestroy();
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
return barcodeView.onKeyDown(keyCode, event) || super.onKeyDown(keyCode, event);
}
}
定义扫描布局文件
<com.journeyapps.barcodescanner.DecoratedBarcodeView
android:id="@+id/barcode_scanner"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:zxing_previewScalingStrategy="centerCrop"
app:zxing_use_texture_view="true"
app:zxing_scanner_layout="@layout/view_custom_finder" />
自定义扫描框视图
继承 ViewfinderView 并重写 onDraw() 方法实现个性化UI:
public class CustomFinderView extends ViewfinderView {
private final Paint cornerPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private final Paint scanLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private float scanLinePosition = 0f;
public CustomFinderView(Context context, AttributeSet attrs) {
super(context, attrs);
cornerPaint.setColor(Color.WHITE);
cornerPaint.setStrokeWidth(8f);
cornerPaint.setStyle(Paint.Style.STROKE);
scanLinePaint.setShader(new LinearGradient(
0, 0, 0, 20,
Color.TRANSPARENT, Color.WHITE, Shader.TileMode.CLAMP));
}
@Override
public void onDraw(Canvas canvas) {
refreshSizes();
if (framingRect == null) return;
drawMaskLayer(canvas);
drawCornerLines(canvas);
drawScanLine(canvas);
postInvalidateDelayed(16, framingRect.left, framingRect.top, framingRect.right, framingRect.bottom);
}
private void drawCornerLines(Canvas canvas) {
int width = framingRect.width() / 4;
int height = framingRect.height() / 4;
// 左上角
canvas.drawLine(framingRect.left, framingRect.top,
framingRect.left + width, framingRect.top, cornerPaint);
canvas.drawLine(framingRect.left, framingRect.top,
framingRect.left, framingRect.top + height, cornerPaint);
// 右上角
canvas.drawLine(framingRect.right, framingRect.top,
framingRect.right - width, framingRect.top, cornerPaint);
canvas.drawLine(framingRect.right, framingRect.top,
framingRect.right, framingRect.top + height, cornerPaint);
// 类似绘制其余两个角...
}
private void drawScanLine(Canvas canvas) {
scanLinePosition += 5;
if (scanLinePosition > framingRect.height()) {
scanLinePosition = 0;
}
float currentY = framingRect.top + scanLinePosition;
canvas.drawRect(framingRect.left + 10, currentY,
framingRect.right - 10, currentY + 8, scanLinePaint);
}
}
替换默认扫描视图
在布局中引用自定义视图:
<!-- view_custom_finder.xml -->
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<your.package.name.CustomFinderView
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</merge>
界面优化技巧
- 调整扫描框尺寸: 使用
app:zxing_framing_rect_width和height属性控制大小 - 位置偏移: 结合透明状态栏使预览区域上移,视觉上提升扫描框位置
- 文字提示位置: 自定义布局中添加TextView并定位至扫描框下方
总结
借助 zxing-android-embedded 可高效实现二维码扫描功能。对于产品化需求,应通过继承机制定制UI表现,包括扫描动画、边框样式及交互反馈,确保符合整体设计规范。同时注意权限管理、异常处理和性能优化,提升用户体验。