当前位置:首页 > 技术 > 正文内容

Android中集成ZXing实现二维码扫描与界面定制

访客 技术 2026年6月28日 2

二维码扫描技术原理

在移动应用开发中,二维码扫描功能通过调用设备摄像头捕获图像,利用解码算法提取其中编码的文本信息。这一过程涉及图像采集、条码识别和数据解析三个核心环节。常见的实现方式是基于开源解码库构建封装组件,以简化集成流程。

使用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_widthheight 属性控制大小
  • 位置偏移: 结合透明状态栏使预览区域上移,视觉上提升扫描框位置
  • 文字提示位置: 自定义布局中添加TextView并定位至扫描框下方

总结

借助 zxing-android-embedded 可高效实现二维码扫描功能。对于产品化需求,应通过继承机制定制UI表现,包括扫描动画、边框样式及交互反馈,确保符合整体设计规范。同时注意权限管理、异常处理和性能优化,提升用户体验。

标签: ZXing

相关文章

Linux crontab 详解

1) crontab 是什么cron 是 Linux 的定时任务守护进程;crontab 是用来编辑/查看“按时间周期执行命令”的表(cron table)。常见两类:用户 crontab:每个用户一份(crontab -e 编辑)系统级 crontab / cron.d:可指定执行用户(/etc/crontab、/etc/cron.d/*)2) crontab 时间...

富文本里可以允许的 HTML 属性

一、所有标签默认允许的安全属性(极少)class        (可选)id           (通常建议禁用)title️ 注意:id 容易被滥用做锚点注入,很多系统直接禁用class 允许的话最好只允许固定前缀(如 editor-*)二、a 标签允许属性<a href="" t...

Mac 安装 Node.js 指南

方法一:通过官网安装包(最简单,适合初学者)如果你只是想快速安装并开始使用,这是最直接的方法。访问 Node.js 官网。页面会显示两个版本:LTS (Recommended For Most Users):长期支持版,最稳定。建议选这个。Current:最新特性版,包含最新功能但可能不够稳定。下载 .pkg 安装包并运行。按照安装向导点击“下一步”即可完成。方法二:使用 Homebrew 安装(...

Dom\HTML_NO_DEFAULT_NS 的副作用:自动加闭合标签

在使用Dom\HTMLDocument时,Dom\HTML_NO_DEFAULT_NS 将禁止在解析过程中设置元素的命名空间, 此设置是为了与DOMDocument向后兼容而存在的。当使用它时,已知的一个副作用就是:自动加闭合标签例如 </img> 为什么会这样?当你使用:Dom\HTML_NO_DEFAULT_NS文档会变成 无命名空间模式,此时内部更接近 XML...

Laravel 事件和监听器创建

在 Laravel 中,使用 Artisan 命令创建 Events(事件) 和 Listeners(监听器) 是非常高效的。你可以通过以下几种方式来实现:1. 手动创建单个 Event如果你只想创建一个事件类,可以使用 make:event 命令:Bashphp artisan make:event UserRegistered执行后,文件将生成在 app/Even...

自定义域名解析神器 dnsmasq

什么是 dnsmasq?dnsmasq 是一个轻量级、功能强大的网络服务工具,专为小型和中等规模网络设计。它是一个综合的网络基础设施解决方案[1]。dnsmasq 能做什么?功能说明应用场景DNS 转发与缓存将 DNS 查询转发到上游服务器(ISP、Google DNS 等),并在本地缓存结果加快 DNS 查询速度,减少外部 DNS 流量本地 DNS解析本地网络设备的主机名,无需编辑&n...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。