简述:这个博客主要记载zxing-android-embedded的简单使用,如何替换相机的布局,如何去掉生成二维码的空白等等一系列问题.
zxing-android-embedded的使用
1.首先添加依赖
implementation 'com.android.support:appcompat-v7:26.1.0' implementation 'com.journeyapps:zxing-android-embedded:3.6.0'
2.生成二维码
private void createQrCode(){ BarcodeEncoder barcodeEncoder = new BarcodeEncoder(); try { BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, 400, 400); bitMatrix =deleteWhite(bitMatrix); //删除二维码周边的空白处 qrCodeBitmap=barcodeEncoder.createBitmap(bitMatrix); qrCodeImg.setImageBitmap(qrCodeBitmap); } catch (WriterException e) { e.printStackTrace(); } }
3.扫描二维码
/** * 扫描二维码 */ private void scanQrCode(){ IntentIntegrator intentIntegrator = new IntentIntegrator(this); intentIntegrator.setDesiredBarcodeFormats(IntentIntegrator.QR_CODE); //设置扫描的类型 intentIntegrator.setOrientationLocked(false); //方向锁定 intentIntegrator.setCaptureActivity(CustomCaptureActivity.class); intentIntegrator.setCameraId(0); //前置相机还是后置相机 intentIntegrator.setBeepEnabled(false); //是否发出成功的声音 intentIntegrator.setBarcodeImageEnabled(true); intentIntegrator.initiateScan(); }
方向锁定的话,你还需要设置CaptureActivity,假如你是按依赖添加的而不是导入源码,那么需要
public class CustomCaptureActivity extends CaptureActivity {
}
在AndroidManifest里面设置
<activity android:name=".custom.CustomCaptureActivity" android:screenOrientation="fullSensor" tools:replace="screenOrientation"/>
在扫描完成之后,他会自动返回到onActivityResult()函数里面
@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, "Cancelled", Toast.LENGTH_LONG).show(); } else { Toast.makeText(this, "Scanned: " + result.getContents(), Toast.LENGTH_LONG).show(); } } else { super.onActivityResult(requestCode, resultCode, data); } }
这里的result.getContents()就是二维码内含的值
删除二维码生成时候的周围的空白
zing-android-embedde原始生成的二维码周围会有很多的空白,所以自己需要删除空白
/** * 删除二维码的空白区域 * @param matrix * @return */ private static BitMatrix deleteWhite(BitMatrix matrix) { int[] rec = matrix.getEnclosingRectangle(); //数字7 代表了留的空白区域的大小 int resWidth = rec[2] + 10; int resHeight = rec[3] + 10; BitMatrix resMatrix = new BitMatrix(resWidth, resHeight); resMatrix.clear(); for (int i = 10; i < resWidth; i++) { for (int j = 10; j < resHeight; j++) { if(matrix.get(i+rec[0],j+rec[1])) resMatrix.set(i,j); } } return resMatrix; }
自定义二维码扫描时候扫描的大小
因为zxing-android-embedded生成的界面比较难看,所以一般需要修改原生的界面。一般是修改源码或者是继承
本文因为是采用依赖导成jar进来的,所以采用的是继承的方式。
public class CustomCaptureActivity extends CaptureActivity { private ImageView oldBackImg; private CustomDecoratedBarcodeView customDecoratedBarcodeView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); oldBackImg = findViewById(R.id.oldBackImg); oldBackImg.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { finish(); } }); } @Override protected DecoratedBarcodeView initializeContent(){ setContentView(R.layout.custom_activity_zxing_capture); customDecoratedBarcodeView= findViewById(R.id.zxing_custom_barcode_scanner); return customDecoratedBarcodeView; }
}
最主要的是inittializeContent()方法,这个方法可以设置除了扫描以外的界面,比如加一个标题栏等等
DecoratedBarcodeView 就是扫描最重要的组成部分,他由两个View组成,第一个BarcodeView就是扫描的窗口,
第二个Viewfinder有效果。 所以我们如果想绘制扫描的界面可以重写Viewfineder的onDraw()方法
package backup.wingos.com.wingbackup.custom; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Rect; import android.util.AttributeSet; import android.util.Log; import com.journeyapps.barcodescanner.ViewfinderView; import backup.wingos.com.wingbackup.R; /** * Created by xiongbo on 2018/11/14. */ public class CustomViewfinderView extends ViewfinderView { private static final String TAG = "CustomViewfinderView"; /** * 画相机四个角落的值 */ private Paint customPaint; /** * 获取相机的区域 */ private Rect frame; /** * 修改这个值 可以修改角落绘制的颜色 */ private int color; /** * 四个角落的宽度 */ private int cornerWidth; /** * 四个角落的厚度 */ private int cornerHeight; /** * 你需要在相机下面显示的文字 */ private String text; /** * 中间横线竖直的位置 */ private int direction; /** * 代表了第一次绘制 */ private boolean isFirst; /** * 是否获取二维码的结果 */ private boolean isResult; /** * 是否退出线程 */ private boolean isExit; private Thread thread; public CustomViewfinderView(Context context, AttributeSet attrs) { super(context, attrs); customPaint = new Paint(); customPaint.setStyle(Paint.Style.FILL); color=getResources().getColor(R.color.colorPrimary); customPaint.setAntiAlias(true); cornerWidth=50; cornerHeight=8; text="Scan the QR code from new phone"; isFirst = true; isResult=false; isExit=false; thread = new Thread(new Runnable() { @Override public void run() { while(!isExit){ setDirection(direction+2); try { thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } } }); thread.start(); } @Override public void onDraw(Canvas canvas) { super.refreshSizes(); if (framingRect == null || previewFramingRect == null) { return; } frame = framingRect; if(isFirst){ isFirst=false; direction=frame.top+10; } customPaint.setColor(color); customPaint.setStrokeWidth((float) 1.5); /** * 绘制四条边框 */ canvas.drawLine(frame.left,frame.top,frame.right,frame.top,customPaint); canvas.drawLine(frame.left,frame.top,frame.left,frame.bottom,customPaint); canvas.drawLine(frame.right,frame.top,frame.right,frame.bottom,customPaint); canvas.drawLine(frame.right,frame.bottom,frame.left,frame.bottom,customPaint); final int width = canvas.getWidth(); final int height = canvas.getHeight(); // 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); isResult=true; } else { customPaint.setAlpha(100); Rect rect = new Rect(frame.left,frame.top,frame.right, direction); canvas.drawRect(rect,customPaint); customPaint.setAlpha(255); customPaint.setStrokeWidth(3); canvas.drawLine(frame.left,direction,frame.right,direction,customPaint); if(direction>=frame.bottom){ direction=frame.top; } } if(isResult){ isExit=true; }else{ isExit=false; } drawCorner(1,canvas); drawCorner(2,canvas); drawCorner(3,canvas); drawCorner(4,canvas); drawText(text,canvas); } public void setColor(int color){ this.color=color; invalidate(); } /** * 绘制四个角落 type: 1--左上 2--右上 3--左下 4--右下 */ private void drawCorner(int type,Canvas canvas){ Rect verticalRect=null; Rect horizontalRect =null; if(type==1){ horizontalRect = new Rect(frame.left,frame.top,frame.left+cornerWidth,frame.top+cornerHeight); verticalRect = new Rect(frame.left,frame.top,frame.left+cornerHeight,frame.top+cornerWidth); }else if(type==2){ horizontalRect = new Rect(frame.right-cornerWidth,frame.top,frame.right,frame.top+cornerHeight); verticalRect = new Rect(frame.right-cornerHeight,frame.top,frame.right,frame.top+cornerWidth); }else if(type==3){ horizontalRect = new Rect(frame.left,frame.bottom-cornerWidth,frame.left+cornerHeight,frame.bottom); verticalRect = new Rect(frame.left,frame.bottom-cornerHeight,frame.left+cornerWidth,frame.bottom); }else{ horizontalRect = new Rect(frame.right-cornerWidth,frame.bottom-cornerHeight,frame.right,frame.bottom); verticalRect = new Rect(frame.right-cornerHeight,frame.bottom-cornerWidth,frame.right,frame.bottom); } canvas.drawRect(horizontalRect,customPaint); canvas.drawRect(verticalRect,customPaint); } public void setText(String text){ this.text=text; } private void drawText(String text,Canvas canvas){ customPaint.setColor(getResources().getColor(R.color.colorWhite)); customPaint.setTextSize(50); canvas.drawText(text,frame.left-30,frame.bottom+100,customPaint); } private void setDirection(int direction){ this.direction=direction; invalidate(); } public void stopThread(){ isExit=true; if(thread!=null){ thread=null; } } }
<?xml version="1.0" encoding="UTF-8"?> <resources> <declare-styleable name="zxing_view"> <attr name="zxing_scanner_layout" format="reference"/> </declare-styleable> <declare-styleable name="zxing_camera_preview"> <attr name="zxing_framing_rect_width" format="dimension" /> //窗口大小 <attr name="zxing_framing_rect_height" format="dimension" /> <attr name="zxing_use_texture_view" format="boolean" /> <attr name="zxing_preview_scaling_strategy" format="enum"> <enum name="centerCrop" value="1" /> <enum name="fitCenter" value="2" /> <enum name="fitXY" value="3" /> </attr> </declare-styleable> <declare-styleable name="zxing_finder"> <attr name="zxing_possible_result_points" format="color"/> <attr name="zxing_result_view" format="color"/> <attr name="zxing_viewfinder_laser" format="color"/> <attr name="zxing_viewfinder_mask" format="color"/> //绘制背景的颜色 </declare-styleable> </resources>
我们自定义的话,可以把这个style复制到自己项目里面。也可以直接用;只要在BarcodeView设置属性就好了
<backup.wingos.com.wingbackup.custom.CustomBarcodeView android:id="@+id/zxing_custom_barcode_surface" android:layout_width="match_parent" android:layout_height="match_parent" app:zxing_framing_rect_height="240dp" app:zxing_framing_rect_width="240dp" /> <backup.wingos.com.wingbackup.custom.CustomViewfinderView android:id="@+id/zxing_custom_viewfinder_view" android:layout_width="match_parent" android:layout_height="match_parent" app:zxing_viewfinder_mask="#757575" />
这样就完成效果了。而且原生的话,关闭会有一定的延时效果,所以我们可以把这个延时关闭掉,影响用户体验
/** * 造成了延时效果 * 本来为 2000000000 修改成了 10000000 */ @Override public void pauseAndWait() { CameraInstance instance = getCameraInstance(); pause(); long startTime = System.nanoTime(); while(instance != null && !instance.isCameraClosed()) { if(System.nanoTime() - startTime > 10000000) { // Don't wait for longer than 2 seconds break; } try { Thread.sleep(1); } catch (InterruptedException e) { break; } } }