最近项目中要使用扫描二维码,于是乎就用到了 zxing-android-embedded 这个由zing库演变过来的android版的三方库,现在把使用心得以及过程进行分享~
话不多说,搞起!
权限:
这里多说一句,我用的是api导包方式(一个小知识点):
api("com.journeyapps:zxing-android-embedded:3.6.0") {
exclude group: 'com.android.support'
}
肯定有朋友问了,为什么不用最常见的 implementation方式呢,好说,上面这种导入方式好处是,不会导致三方库的依赖包和项目本地的依赖包产生冲突,例如:com.android.support:appcompat-v7:28.0.0-beta01包,所以我建议各位以后导库都用上面的方式,一劳永逸,没懂?无所谓跟着做肯定没毛病,当然前提你的AS版本 >= 3.0的,要不然当我没说。
新建一个类 MyViewFinderView 继承 ViewfinderView 类,并重写它的两个方法:onDraw(Canvas canvas) 和 refreshSizes()方法。
onDraw(Canvas canvas) 里的内容去源码中copy即可,下面是我自己改的自定义样式代码:
@Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
refreshSizes();
if (framingRect == null || previewFramingRect == null) {
return;
}
final Rect frame = framingRect;
final Rect previewFrame = previewFramingRect;
final int width = canvas.getWidth();
final int height = canvas.getHeight();
// 注意此处如果不进行赋值,就会走下面的else方法,绘制图形。我比较懒,就直接引入了一个扫描边框图片。
resultBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.sc_bg);
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);
// 此处是我自己写绘制的扫描线
drawScLine(liney, canvas);
if (resultBitmap != null) {
// Draw the opaque result bitmap over the scanning rectangle
paint.setAlpha(CURRENT_POINT_OPACITY);
canvas.drawBitmap(resultBitmap, null, frame, paint);
} else {
// Draw a red "laser scanner" line through the middle to show decoding is active
paint.setColor(laserColor);
paint.setAlpha(SCANNER_ALPHA[scannerAlpha]);
scannerAlpha = (scannerAlpha + 1) % SCANNER_ALPHA.length;
final int middle = frame.height() / 2 + frame.top;
canvas.drawRect(frame.left + 2, middle - 1, frame.right - 1, middle + 2, paint);
final float scaleX = frame.width() / (float) previewFrame.width();
final float scaleY = frame.height() / (float) previewFrame.height();
final int frameLeft = frame.left;
final int frameTop = frame.top;
// draw the last possible result points
if (!lastPossibleResultPoints.isEmpty()) {
paint.setAlpha(CURRENT_POINT_OPACITY / 2);
paint.setColor(resultPointColor);
float radius = POINT_SIZE / 2.0f;
for (final ResultPoint point : lastPossibleResultPoints) {
canvas.drawCircle(
frameLeft + (int) (point.getX() * scaleX),
frameTop + (int) (point.getY() * scaleY),
radius, paint
);
}
lastPossibleResultPoints.clear();
}
// draw current possible result points
if (!possibleResultPoints.isEmpty()) {
paint.setAlpha(CURRENT_POINT_OPACITY);
paint.setColor(resultPointColor);
for (final ResultPoint point : possibleResultPoints) {
canvas.drawCircle(
frameLeft + (int) (point.getX() * scaleX),
frameTop + (int) (point.getY() * scaleY),
POINT_SIZE, paint
);
}
// swap and clear buffers
final List temp = possibleResultPoints;
possibleResultPoints = lastPossibleResultPoints;
lastPossibleResultPoints = temp;
possibleResultPoints.clear();
}
// Request another update at the animation interval, but only repaint the laser line,
// not the entire viewfinder mask.
postInvalidateDelayed(ANIMATION_DELAY,
frame.left - POINT_SIZE,
frame.top - POINT_SIZE,
frame.right + POINT_SIZE,
frame.bottom + POINT_SIZE);
}
}
refreshSizes()方法内容:
@Override
protected void refreshSizes() {
if (cameraPreview == null) {
return;
}
// 设置二维码扫描框大小,正常要自己适配屏幕大小,按照比例写的,我比较懒写死了,嘿嘿。
framingRect = new Rect(165, 432, 915, 1182);//二维码框
Rect previewFramingRect = cameraPreview.getPreviewFramingRect();
if (framingRect != null && previewFramingRect != null) {
this.framingRect = framingRect;
this.previewFramingRect = previewFramingRect;
}
}
附赠我的扫描线绘制方法以及动画方法and启动动画逻辑:
初始化画笔:
/**
* 初始化画笔
*
* @param paintSize 画笔大小
* @param paintColor 画笔颜色
* @return
*/
private Paint initPaint(int paintSize, int paintColor) {
Paint paint = new Paint();
//设置抗锯齿
paint.setAntiAlias(true);
//设置画笔笔尖样式
paint.setStrokeCap(Paint.Cap.ROUND);
//设置填充模式,默认为FILL
paint.setStyle(Paint.Style.STROKE);
//设置画笔大小
paint.setStrokeWidth(paintSize);
//设置颜色
paint.setColor(getResources().getColor(paintColor));
return paint;
}
绘制扫描线:
private void drawScLine(int y, Canvas canvas) {
Paint paint = initPaint(8, R.color.colorAccent);
Path line = new Path();
int x = framingRect.left + framingRect.width() / 10 * 2;
line.moveTo(x, y);
line.lineTo(x + framingRect.width() / 10 * 6, y);
canvas.drawPath(line, paint);
}
扫描线扫描动作动画:
private void startAnimator() {
animator = ValueAnimator.ofInt(framingRect.top, framingRect.bottom);
animator.setDuration(5000);
animator.setRepeatCount(ValueAnimator.INFINITE);//无限循环
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
Integer value = (Integer) animation.getAnimatedValue();
liney = value;
Log.e("valuevaluevalue", value + "");
myhandler.sendEmptyMessage(0);
}
});
animator.start();
}
为了照顾懒癌晚期患者,我handler都送给你:
public static class Myhandler extends android.os.Handler {
private WeakReference weakReference;
private MyViewFinderView myViewFinderView;
public Myhandler(MyViewFinderView myViewFinderView) {
weakReference = new WeakReference<>(myViewFinderView);
}
@Override
public void handleMessage(Message msg) {
myViewFinderView = weakReference.get();
myViewFinderView.invalidate();
}
}
在onWindowFocusChanged()方法中监听进行初始化handler和动画的启动操作:
@Override
public void onWindowFocusChanged(boolean hasWindowFocus) {
super.onWindowFocusChanged(hasWindowFocus);
if (hasWindowFocus) {
myhandler = new Myhandler(this);
if (firstLoad) {
startAnimator();
firstLoad = false;
}
}
}
记得在onDetachedFromWindow()方法中结束动画,减少内存开销:
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
if (animator != null) {
animator.cancel();
}
}
在你要显示的扫描页的xml布局文件中引入我们的自定义控件:
整体myviewfinder.xml如下,懒癌患者直接copy即可:
我比较懒,直接给你们代码了:
/**
* 扫描二维码页面
*/
public class ScActivity extends AppCompatActivity {
private CaptureManager captureManager;
private DecoratedBarcodeView mDBV;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sc);
mDBV = findViewById(R.id.dbv_custom);
//重要代码,初始化捕获
captureManager = new CaptureManager(this, mDBV);
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();
}
}
页面的xml也给你们:
初始化:
private void initScan() {
integrator = new IntentIntegrator(this);
integrator.setPrompt("请扫描二维码"); //底部的提示文字,设为""可以置空
integrator.setCameraId(0); //前置或者后置摄像头
integrator.setBeepEnabled(true); //扫描成功的「哔哔」声,默认开启
integrator.setCaptureActivity(ScActivity.class); //设置扫描activity
}
调用:
integrator.initiateScan();
搞定收工~
最后几句:我是把自定义和使用合到一起写了,因为我比较懒嘛~按照我这个步骤就就可以使用,粗心大意的多检查检查就行了,我这几乎都是把源码贴上来了,所以就不发源码了。(就这点东西还用得着源码?小声嘀咕)