android-基于ZXing Android Embedded实现仿微信二维码扫描功能

前言:

网上也有非常多基于二维码zxing实现自定义需求,但是搜索了一大圈,都没找到自己想要的那种效果,本文基于综合各大大神资料,自己绘制了一个实现zxing二维码,仿微信实现了双击放大缩小,二维码边角,及去除ZXing Android Embedded原生红线效果,仿微信绘制了线条滚动效果。

eg

在这里插入图片描述

导入aar

implementation (‘com.journeyapps:zxing-android-embedded:3.6.0’){ transitive = false }
implementation ‘com.google.zxing:core:3.3.2’
implementation ‘com.tbruyelle.rxpermissions2:rxpermissions:0.9.4@aar’

代码

1.闪光灯

//获取CompoundBarcodeView类
private CompoundBarcodeView barcodeView;
    @Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.qrcode);
    .....
    barcodeView = (CompoundBarcodeView) findViewById(R.id.barcode_scanner);
	 ....
	flashlight.setOnClickListener(v -> {
        if (isLightOn) {
      		//闪光灯关闭
            barcodeView.setTorchOff();
            flashlight.setImageResource(R.drawable.light_close);
        } else {
        		//闪光灯打开
            barcodeView.setTorchOn();
            flashlight.setImageResource(R.drawable.light_open);
        }
        isLightOn = !isLightOn;
    });
    // 如果没有闪光灯功能,就去掉相关按钮
    if (!hasFlash()) {
        flashlight.setVisibility(View.GONE);
    }

}

这里主要调用zxing已经给我们写好的接口CompoundBarcodeView下的接口barcodeView.setTorchOn和Off,我们直接引用就可以了。

2.四个边角框

我们看ZXing Android Embedded源码可以知道,我们可以重写DecoratedBarcodeView类的R.layout.zxing_barcode_scanner的布局

/**
 * Initialize the view with the xml configuration based on styleable attributes.
 *
 * @param attrs The attributes to use on view.
 */
private void initialize(AttributeSet attrs) {
    // Get attributes set on view
    TypedArray attributes = getContext().obtainStyledAttributes(attrs, R.styleable.zxing_view);

    int scannerLayout = attributes.getResourceId(
            R.styleable.zxing_view_zxing_scanner_layout, R.layout.zxing_barcode_scanner);

    attributes.recycle();

    inflate(getContext(), scannerLayout, this);

    barcodeView = (BarcodeView) findViewById(R.id.zxing_barcode_surface);

    if (barcodeView == null) {
        throw new IllegalArgumentException(
            "There is no a com.journeyapps.barcodescanner.BarcodeView on provided layout " +
            "with the id \"zxing_barcode_surface\

点开之类,我写上备注

<merge xmlns:android="http://schemas.android.com/apk/res/			android">
	//ScaleBarcodeView 这个对应修改整个背景不分(例如放大缩小)
<com.example.qrcodeactivity.qrcode.ScaleBarcodeView
    android:id="@+id/zxing_barcode_surface"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />
//CustomViewFinderView 这个对应修改扫描框(例如边角,红线部分)
<com.example.qrcodeactivity.qrcode.CustomViewFinderView
    android:id="@+id/zxing_viewfinder_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />
//底部自定义文字
<TextView
    android:id="@+id/zxing_status_view"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="bottom|center_horizontal"
    android:background="@color/zxing_transparent"
    android:text="@string/zxing_msg_default_status"
    android:textColor="@color/zxing_status_text" />
</merge>

这里我们要实现去红线和四个角,所以我们要继承ViewfinderView重写ondraw部分代码

	/**
 * desc:重写扫描框类
 * author:ccw
 * date:2019-12-27
 * time:22:45
	 */
public class CustomViewFinderView extends ViewfinderView {
private int screenWidth = 0;
private int screenHeight = 0;
private RectF buttonRect;
private String text_btn = "个性化需求";
/**
 * 重绘时间间隔
 */
private static long CUSTOME_ANIMATION_DELAY = 16;
/**
 * 边角线颜色
 */

private int mLineColor = getContext().getResources().getColor(R.color.c_a_green);
/**
 * 线性梯度各个位置对应的颜色值
 */
private Rect nowScanRect;
/**
 * 边角线厚度 (建议使用dp)
 */

private float mLineDepth = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 2f, getResources().getDisplayMetrics());
/**
 * "边角线长度/扫描边框长度"的占比 (比例越大,线越长)
 */

private float mLineRate = 0.05f;
/**
 * 扫描线起始位置
 */

private int mScanLinePosition = 0;
/**
 * 扫描线每次重绘的移动距离
 */

private float mScanLineDy = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 3f, getResources().getDisplayMetrics());

/**
 * 线性梯度
 */
private LinearGradient mLinearGradient;
/**
 * 线性梯度位置
 */

private float[] mPositions = {0f, 0.5f, 1f};

/**
 * 扫描线厚度
 */

private float mScanLineDepth = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1f, getResources().getDisplayMetrics());
//扫描线渐变色
private int laserColor_center = getContext().getResources().getColor(R.color.c_a_green);

private int laserColor_light = getContext().getResources().getColor(R.color.c_a_green);

private int[] mScanLineColor = {laserColor_light, laserColor_center, laserColor_light};


private float mDist = 0;

public CustomViewFinderView(Context context, AttributeSet attrs) {
    super(context, attrs);
    init();
}

private void init() {
    WindowManager windowManager = ((Activity) getContext()).getWindowManager();
    DisplayMetrics displayMetrics = new DisplayMetrics();
    windowManager.getDefaultDisplay().getMetrics(displayMetrics);
    screenWidth = displayMetrics.widthPixels;
    screenHeight = displayMetrics.heightPixels;
    int w = screenWidth * 3 / 5;
    int marginL = screenWidth / 5;
    int marginT = screenHeight / 4;
    nowScanRect = new Rect(marginL, marginT, w + marginL, w + marginT);
}

@SuppressLint("DrawAllocation")
@Override
public void onDraw(Canvas canvas) {
    refreshSizes();
    if (framingRect == null || previewFramingRect == null) {
        return;
    }
    Rect frame = nowScanRect;
  //  Rect frame =  cameraPreview.getFramingRect();
    Rect previewFrame = previewFramingRect;
    int width = canvas.getWidth();
    int height = canvas.getHeight();
    if (resultBitmap != null) {
        paint.setColor(resultColor);
    } else {
        paint.setColor(maskColor);
    }

    canvas.drawRect(0f, 0f, width, frame.top, paint);
    canvas.drawRect(0f, frame.top, frame.left, (frame.bottom + 1), paint);
    canvas.drawRect((frame.right + 1), frame.top, width, (frame.bottom + 1), paint);
    canvas.drawRect(0f, (frame.bottom + 1), width, height, paint);

    //  drawText(canvas, frame)

  //  drawButton(canvas, frame);
    ////绘制4个角
    paint.setColor(mLineColor);
	//
	// 定义画笔的颜色
    //左上-横线
    canvas.drawRect(frame.left - mLineDepth,
            frame.top - mLineDepth,
            frame.left + frame.width() * mLineRate,
            frame.top, paint);
    //左上-纵线
    canvas.drawRect(frame.left - mLineDepth, frame.top, frame.left, frame.top + frame.height() * mLineRate, paint);
    //右上-横线
    canvas.drawRect(frame.right - frame.width() * mLineRate, frame.top - mLineDepth, frame.right + mLineDepth, frame.top, paint);
    //右上-纵线
    canvas.drawRect(frame.right, frame.top - mLineDepth, frame.right + mLineDepth, frame.top + frame.height() * mLineRate, paint);
    //左下-横线
    canvas.drawRect(frame.left - mLineDepth, frame.bottom, frame.left + frame.width() * mLineRate, frame.bottom + mLineDepth, paint);
    //左下-纵线
    canvas.drawRect(frame.left - mLineDepth, frame.bottom - frame.height() * mLineRate, frame.left, frame.bottom, paint);
    //右下-横线
    canvas.drawRect(frame.right - frame.width() * mLineRate, frame.bottom, frame.right + mLineDepth, frame.bottom + mLineDepth, paint);
    //右下-纵线
    canvas.drawRect(frame.right, frame.bottom - frame.height() * mLineRate, frame.right + mLineDepth, frame.bottom + mLineDepth, paint);
    if (resultBitmap != null) {
        paint.setAlpha(ViewfinderView.CURRENT_POINT_OPACITY);
        canvas.drawBitmap(resultBitmap, null, frame, paint);
    } else {
        //  drawLaserLine(canvas,frame)
        // 绘制扫描线
        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);

        int scaleX = frame.width() / previewFrame.width();
        int scaleY = frame.height() / 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(ViewfinderView.CURRENT_POINT_OPACITY);
            paint.setColor(resultPointColor);
            for (ResultPoint point : currentPossible) {
                canvas.drawCircle((frameLeft + (point.getX() * scaleX)), (frameTop + (point.getY() * scaleY)), ViewfinderView.POINT_SIZE, paint);
            }

        }

        if (currentLast != null) {
            paint.setAlpha(ViewfinderView.CURRENT_POINT_OPACITY / 2);

            paint.setColor(resultPointColor);

            float radius = ViewfinderView.POINT_SIZE / 2.0f;

            for (ResultPoint point : currentLast) {
                canvas.drawCircle((frameLeft + (point.getX() * scaleX)), (frameTop + (point.getY() * scaleY)), radius, paint);
            }

        }

    }// Request another update at the animation interval, but only repaint the laser line, // not the entire viewfinde

// rmask.
    postInvalidateDelayed(CUSTOME_ANIMATION_DELAY, frame.left, frame.top, frame.right, frame.bottom);

}

private void drawButton(Canvas canvas, Rect mScanRect) {
    Paint buttonPaint = new Paint();
    buttonPaint.setAntiAlias(true);
    buttonPaint.setColor(getContext().getResources().getColor(R.color.c_white));
    buttonPaint.setStrokeWidth(1f);
    buttonPaint.setStyle(Paint.Style.STROKE);

    int height = CommonUtils.dp2px(getContext(), 40);

    int left = mScanRect.left + (mScanRect.right - mScanRect.left) / 6;

    int top = mScanRect.bottom + CommonUtils.dp2px(getContext(), 48);

    int right = mScanRect.right - (mScanRect.right - mScanRect.left) / 6;

    int bottom = mScanRect.bottom + CommonUtils.dp2px(getContext(), 48) + height;

    buttonRect = new RectF(left, top, right, bottom);
    canvas.drawRoundRect(buttonRect, CommonUtils.dp2px(getContext(), 20), CommonUtils.dp2px(getContext(), 20), buttonPaint);


    buttonPaint.setColor(getContext().getResources().getColor(R.color.c_white));
    buttonPaint.setTextSize(CommonUtils.dp2px(getContext(), 14));
    buttonPaint.setStyle(Paint.Style.FILL);
    buttonPaint.setTextAlign(Paint.Align.CENTER);

    Paint.FontMetricsInt fontMetrics = buttonPaint.getFontMetricsInt();

    // var baseLine = buttonRect.centerY() + (fontMetrics.descent - fontMetrics.ascent) / 2 - fontMetrics.descent
    int baseLine = (int) ((buttonRect.top + buttonRect.bottom - fontMetrics.top - fontMetrics.bottom) / 2);
    canvas.drawText(text_btn, buttonRect.centerX(), baseLine, buttonPaint);
}

3.0双击放大缩小和双指放大缩小功能

这里我们要实现双击放大缩小和双指放大缩小功能,所以我们要继承BarcodeView重写

public class ScaleBarcodeView extends BarcodeView {

private float mDist = 0;
//扩展增加双击放大缩小操作 ccw
private static int timeout = 300;//双击间三百毫秒延时
private int clickCount = 0;//记录连续点击次数
private Handler handler;

public ScaleBarcodeView(Context context) {
    super(context);
}

public ScaleBarcodeView(Context context, AttributeSet attrs) {
    super(context, attrs);
    handler = new Handler();
}

public ScaleBarcodeView(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
}


@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouchEvent(MotionEvent event) {

    int action = event.getAction();
    if (event.getPointerCount() > 1) {
        // handle multi-touch events
        if (action == MotionEvent.ACTION_POINTER_DOWN) {
            mDist = getFingerSpacing(event);
        } else if (action == MotionEvent.ACTION_MOVE) {
            CameraInstance cameraInstance = getCameraInstance();
            if (cameraInstance != null) {
                cameraInstance.changeCameraParameters(parameters -> {
                    handleZoom(event, parameters);
                    return parameters;
                });
            }
        }
    } else if (event.getPointerCount() == 1) {
        if (action == MotionEvent.ACTION_DOWN) {
            clickCount++;
            handler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    if (clickCount == 2) {
                        CameraInstance cameraInstance = getCameraInstance();
                        if (cameraInstance != null) {
                            cameraInstance.changeCameraParameters(parameters -> {
                                handleScaleZoom(parameters);
                                return parameters;
                            });
                        }
                    }
                    handler.removeCallbacksAndMessages(null);
                    //清空handler延时,并防内存泄漏
                    clickCount = 0;//计数清零
                }
            }, timeout);
        }
    }
    return true;
}

private void handleZoom(MotionEvent event, Camera.Parameters params) {
    int maxZoom = params.getMaxZoom();
    int zoom = params.getZoom();
    float newDist = getFingerSpacing(event);
    if (newDist > mDist) {
        //zoom in
        if (zoom < maxZoom)
            zoom++;
    } else if (newDist < mDist) {
        //zoom out
        if (zoom > 0)
            zoom--;
    }
    mDist = newDist;
    params.setZoom(zoom);
}

private void handleScaleZoom(Camera.Parameters params) {
    int maxZoom = params.getMaxZoom();
    int zoom = params.getZoom();
    if (zoom < maxZoom / 2) {
        params.setZoom(maxZoom);
    } else {
        params.setZoom(1);
    }
}

/**
 * Determine the space between the first two fingers
 */
private float getFingerSpacing(MotionEvent event) {
    float x = event.getX(0) - event.getX(1);
    float y = event.getY(0) - event.getY(1);
    return (float) Math.sqrt(x * x + y * y);
}
}

这样就行了,下面我会放上demo,需要的兄弟直接github下载下来研究下,有用到的兄弟姐妹点点关注
点关注不迷路,打个小赏把~~

Github地址: https://github.com/ccwccw123/android-qrcode/tree/master

发布了7 篇原创文章 · 获赞 1 · 访问量 967

猜你喜欢

转载自blog.csdn.net/u013285894/article/details/103927190
今日推荐