安卓扫描二维码功能:zxing

需求:实现扫描二维码验证身份。(服务端这部分会提供一个二维码,扫描二维码会生成一个token,根据token的结果向某个url发送网络连接请求,服务端返回验证结果。我只负责安卓扫码和网络连接请求部分)。

基本扫码功能

1.引入google开源库:

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

网上大部分使用的是zxing这个开源库,资料比较多,所以我也用了。。哈哈

2.创建菜单栏,里面增加item为扫描二维码。然后创建IntentIntegrator对象,initiateScan开始扫描。其中IntentIntegrator对象有一些set函数,这里用到的一个是CapacityActivity,默认不set的话是用默认的捕获活动来扫描,这里是自己自定义了一个扫码样式所以显式指定了一下。setPrompt是扫描框下面的一行字。

@Override
    public boolean onOptionsItemSelected(MenuItem item) {
        if(item.getItemId()==R.id.qr_code){
            IntentIntegrator intentIntegrator = new IntentIntegrator(NewMainActivity.this);
            intentIntegrator.setCaptureActivity(CustomCaptureActivity.class);
            intentIntegrator.setPrompt("将二维码放入框内,即可自动扫描");
            intentIntegrator.initiateScan();

        }

3.重写onActivityResult方法接收扫描结果。

  @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        IntentResult result = IntentIntegrator.parseActivityResult(requestCode,resultCode,data);
        if(result==null) {
            super.onActivityResult(requestCode, resultCode, data);
        }
        if (result.getContents() == null) {
            Toast.makeText(this, "取消扫描", Toast.LENGTH_SHORT).show();
        } else {
            Toast.makeText(this, result.getContents(), Toast.LENGTH_SHORT).show();
        }
   }

这几部完成之后,基本的扫码功能就完成了。但是扫码的时候你会发现扫描过程屏幕会横过来,因为其默认扫描界面是横屏,可以在manifest中指定。设置为竖屏。

 <activity
            android:name=".qrcode.CustomCaptureActivity"    
            android:theme="@style/AppTheme"
            android:screenOrientation="portrait"
            tools:replace="screenOrientation" />

基本功能完成了,但是界面比较丑。还可以自定义扫码界面的样式。

自定义扫码界面

1.源码中可以看到CapacityActivity这个活动,之前做扫码功能也主要由这个活动完成,可以直接copy这个活动,创建自己的扫码活动,CustomCapacityActivity,在manifest中进行活动的声明。然后就可以用setCapacityActivity来指定扫码活动了。完美替换。如上。如果能扫码成功,表示替换成功。

2.修改扫码布局

新创建的扫码活动使用的还是源码的布局,我们也不能修改,所以copy一份出来(zxing_capacity),进行修改(activity_zxing_layout)。然后修改customCapacityActivity的布局。

 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_zxing_layout);
    }

3.自定义样式

都copy出来了就可以自定义样式了。研究DecoratedBarcodeView会发现使用的布局是zxing_barcode_scanner。同样把这个布局copy出来。custom_barcode_scanner.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent" android:layout_height="match_parent">
    <com.journeyapps.barcodescanner.BarcodeView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/zxing_barcode_surface"/>

    <com.example.qrcode.CustomViewfinderView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/zxing_viewfinder_view"/>

    <TextView android:id="@+id/zxing_status_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginTop="160dp"
        android:background="@color/zxing_transparent"
        android:text="@string/zxing_msg_default_status"
        android:textColor="@color/zxing_status_text"/>

</FrameLayout>

让DecoratedBarcodeView加载新定义布局,而不是默认的布局。

<?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:orientation="vertical">

    <com.journeyapps.barcodescanner.DecoratedBarcodeView
        android:id="@+id/zxing_barcode_scanner"

        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:zxing_framing_rect_width="250dp"
        app:zxing_framing_rect_height="250dp"
        app:zxing_preview_scaling_strategy="centerCrop"
        app:zxing_scanner_layout="@layout/custom_barcode_scanner"
        app:zxing_use_texture_view="true" />

</LinearLayout>

开始自定义扫描视图,继承ViewfinderView重写onDraw方法。

public class CustomViewfinderView extends ViewfinderView {
    /**
     * 重绘时间间隔
     */
    public static final long CUSTOME_ANIMATION_DELAY = 16;

    /* ******************************************    边角线相关属性    ************************************************/

    /**
     * "边角线长度/扫描边框长度"的占比 (比例越大,线越长)
     */
    public float mLineRate = 0.1F;

    /**
     * 边角线厚度 (建议使用dp)
     */
    public float mLineDepth =  TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 4, getResources().getDisplayMetrics());

    /**
     * 边角线颜色
     */
    public int mLineColor = Color.RED;

    /* *******************************************    扫描线相关属性    ************************************************/

    /**
     * 扫描线起始位置
     */
    public int mScanLinePosition = 0;

    /**
     * 扫描线厚度
     */
    public float mScanLineDepth = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 4, getResources().getDisplayMetrics());

    /**
     * 扫描线每次重绘的移动距离
     */
    public float mScanLineDy = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 3, getResources().getDisplayMetrics());

    /**
     * 线性梯度
     */
    public LinearGradient mLinearGradient;

    /**
     * 线性梯度位置
     */
    public float[] mPositions = new float[]{0f, 0.5f, 1f};

    /**
     * 线性梯度各个位置对应的颜色值
     */
    public int[] mScanLineColor = new int[]{0x00FFFFFF, Color.RED, 0x00FFFFFF};


    public CustomViewfinderView(Context context, AttributeSet attrs) {
        super(context, attrs);

    }

   @Override
    protected void refreshSizes() {
        if(cameraPreview == null) {
            return;
        }
        Rect framingRect = cameraPreview.getFramingRect();
        Rect previewFramingRect = cameraPreview.getPreviewFramingRect();
        if(framingRect != null && previewFramingRect != null) {
            this.framingRect = framingRect;
            this.previewFramingRect = previewFramingRect;
        }
    }

    @Override
    public void onDraw(Canvas canvas) {
        refreshSizes();
        if (framingRect == null || previewFramingRect == null) {
            return;
        }

        Rect frame = framingRect;
        Rect previewFrame = previewFramingRect;

        int width = canvas.getWidth();
        int height = canvas.getHeight();

        //绘制4个角
        paint.setColor(mLineColor);
        canvas.drawRect(frame.left, frame.top, frame.left + frame.width() * mLineRate, frame.top + mLineDepth, paint);
        canvas.drawRect(frame.left, frame.top, frame.left + mLineDepth, frame.top + frame.height() * mLineRate, paint);

        canvas.drawRect(frame.right - frame.width() * mLineRate, frame.top, frame.right, frame.top + mLineDepth, paint);
        canvas.drawRect(frame.right - mLineDepth, frame.top, frame.right, frame.top + frame.height() * mLineRate, paint);

        canvas.drawRect(frame.left, frame.bottom - mLineDepth, frame.left + frame.width() * mLineRate, frame.bottom, paint);
        canvas.drawRect(frame.left, frame.bottom - frame.height() * mLineRate, frame.left + mLineDepth, frame.bottom, paint);

        canvas.drawRect(frame.right - frame.width() * mLineRate, frame.bottom - mLineDepth, frame.right, frame.bottom, paint);
        canvas.drawRect(frame.right - mLineDepth, frame.bottom - frame.height() * mLineRate, frame.right, frame.bottom, paint);

        // Draw the exterior (i.e. outside the framing rect) darkened
        paint.setColor(resultBitmap != null ? resultColor : maskColor);
        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);

        if (resultBitmap != null) {
            // Draw the opaque result bitmap over the scanning rectangle
            paint.setAlpha(CURRENT_POINT_OPACITY);
            canvas.drawBitmap(resultBitmap, null, frame, paint);
        } else {
            // 绘制扫描线
            mScanLinePosition += mScanLineDy;
            if(mScanLinePosition > frame.height()){
                mScanLinePosition = 0;
            }
            mLinearGradient = new LinearGradient(frame.left, frame.top + mScanLinePosition, frame.right, frame.top + mScanLinePosition, mScanLineColor, mPositions, Shader.TileMode.CLAMP);
            paint.setShader(mLinearGradient);
            canvas.drawRect(frame.left, frame.top + mScanLinePosition, frame.right, frame.top + mScanLinePosition + mScanLineDepth, paint);
            paint.setShader(null);

            float scaleX = frame.width() / (float) previewFrame.width();
            float scaleY = frame.height() / (float) previewFrame.height();

            List<ResultPoint> currentPossible = possibleResultPoints;
            List<ResultPoint> currentLast = lastPossibleResultPoints;
            int frameLeft = frame.left;
            int frameTop = frame.top;
            if (currentPossible.isEmpty()) {
                lastPossibleResultPoints = null;
            } else {
                possibleResultPoints = new ArrayList<>(5);
                lastPossibleResultPoints = currentPossible;
                paint.setAlpha(CURRENT_POINT_OPACITY);
                paint.setColor(resultPointColor);
                for (ResultPoint point : currentPossible) {
                    canvas.drawCircle(frameLeft + (int) (point.getX() * scaleX),
                            frameTop + (int) (point.getY() * scaleY),
                            POINT_SIZE, paint);
                }
            }
            if (currentLast != null) {
                paint.setAlpha(CURRENT_POINT_OPACITY / 2);
                paint.setColor(resultPointColor);
                float radius = POINT_SIZE / 2.0f;
                for (ResultPoint point : currentLast) {
                    canvas.drawCircle(frameLeft + (int) (point.getX() * scaleX),
                            frameTop + (int) (point.getY() * scaleY),
                            radius, paint);
                }
            }
        }

        // Request another update at the animation interval, but only repaint the laser line,
        // not the entire viewfinder mask.
        postInvalidateDelayed(CUSTOME_ANIMATION_DELAY,
                frame.left,
                frame.top,
                frame.right,
                frame.bottom);
    }
}

更加详细的内容参考这里:https://www.jianshu.com/p/b85812b6f7c1

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!
要在Android应用中使用ZXing库来实现扫描二维码功能,您可以按照以下步骤操作: 1. 在您的项目中添加ZXing库的依赖。您可以在build.gradle文件中添加以下依赖: ```gradle implementation 'com.google.zxing:core:3.4.0' implementation 'com.journeyapps:zxing-android-embedded:3.6.0' ``` 2. 在您的布局文件中添加一个用于显示摄像头预览的SurfaceView: ```xml <SurfaceView android:id="@+id/surfaceView" android:layout_width="match_parent" android:layout_height="match_parent" /> ``` 3. 在您的代码中创建一个ZXing库的核心对象和一个用于处理扫描结果的回调函数: ```java private CaptureManager capture; private ZXingScannerView scannerView; private void initScanner() { scannerView = new ZXingScannerView(this); setContentView(scannerView); capture = new CaptureManager(this, scannerView); capture.initializeFromIntent(getIntent(), null); capture.decode(); scannerView.setResultHandler(new ResultHandler()); } private class ResultHandler implements ZXingScannerView.ResultHandler { @Override public void handleResult(Result rawResult) { // 处理扫描结果 String result = rawResult.getText(); // 在此处添加您的处理逻辑 // ... // 重新开始扫描 scannerView.resumeCameraPreview(this); } } ``` 4. 在您的Activity的onCreate方法中调用initScanner()方法来初始化扫描器: ```java @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); initScanner(); } ``` 5. 在您的Activity的onResume方法中调用capture.onResume()和scannerView.onResume()方法来恢复扫描器: ```java @Override protected void onResume() { super.onResume(); capture.onResume(); scannerView.onResume(); } ``` 6. 在您的Activity的onPause方法中调用capture.onPause()和scannerView.onPause()方法来暂停扫描器: ```java @Override protected void onPause() { super.onPause(); capture.onPause(); scannerView.onPause(); } ``` 7. (可选)您可以在您的Activity的onDestroy方法中调用capture.onDestroy()方法来释放扫描器: ```java @Override protected void onDestroy() { super.onDestroy(); capture.onDestroy(); } ``` 现在您的应用已经可以使用ZXing库来扫描二维码了。在您的应用中启动这个Activity,您将看到一个用于扫描二维码的摄像头预览界面。当您扫描到一个二维码时,它的内容将会传递给您在第3步中创建的ResultHandler对象的handleResult方法中。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值