使用的是集成华为扫描的SDK,UI界面借鉴的是谷歌官方的Zxing项目中的自定义view,两者结合实现。
先上效果图:
- 先在项目根级别(build.gradle)当中配置HMS Core SDK的Maven仓地址。
// 配置HMS Core SDK的Maven仓地址。
maven {url 'https://developer.huawei.com/repo/'}`
2. 在对应module的build.gradle(Module:app)中添加依赖
dependencies {
implementation 'com.huawei.hms:scanplus:1.3.2.300'
}
- 在清单文件里面添加静态权限
- 还需要在代码中申请相机的动态权限
public static final int DEFINED_CODE = 222;
public static final int DECODE = 1;
//跳转到扫描界面的监听中调用
requestPermission(DEFINED_CODE, DECODE);
private void requestPermission(int requestCode, int mode) {
ActivityCompat.requestPermissions(
this,
new String[]{Manifest.permission.CAMERA, Manifest.permission.READ_EXTERNAL_STORAGE},
requestCode);
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
if (permissions == null || grantResults == null) {
return;
}
if (grantResults.length < 2 || grantResults[0] != PackageManager.PERMISSION_GRANTED || grantResults[1] != PackageManager.PERMISSION_GRANTED) {
return;
}
//Customized View Mode 使用的是自定义扫码界面 所以这块权限请求成功后才跳转到扫码界面
if (requestCode == DEFINED_CODE) {
Intent intent = new Intent(this, CustomizedViewActivity.class);
this.startActivityForResult(intent, REQUEST_CODE_DEFINE);
}
}
//此处是扫描界面处理完成的扫描结果回调
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode != RESULT_OK || data == null) {
return;
}
//Customized View
if (requestCode == REQUEST_CODE_DEFINE) {
HmsScan obj = data.getParcelableExtra(CustomizedViewActivity.SCAN_RESULT);
if (obj != null) {
//拿到扫描信息根据自己需求自行处理
Toast.makeText(this, obj.toString(), Toast.LENGTH_SHORT).show();
}
}
}
5.**扫描界面 **
xml显示:
activity当中处理
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.os.Bundle;
import android.provider.MediaStore;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.widget.frameLayout;
import android.widget.LinearLayout;
import com.example.jianzhuapplication.R;
import com.huawei.hms.hmsscankit.OnResultCallback;
import com.huawei.hms.hmsscankit.RemoteView;
import com.huawei.hms.hmsscankit.ScanUtil;
import com.huawei.hms.ml.scan.HmsScan;
import com.huawei.hms.ml.scan.HmsScanAnalyzerOptions;
import java.io.IOException;
import androidx.appcompat.app.AppCompatActivity;
public class CustomizedViewActivity extends AppCompatActivity {
private frameLayout rim;
private int mScreenWidth;
private int mScreenHeight;
//The width and height of scan_view_finder is both 240 dp.
final int SCAN_frame_SIZE = 240;
private RemoteView remoteView;//Declare the key. It is used to obtain the value returned from Scan Kit.
public static final String SCAN_RESULT = "scanResult";
public static final int REQUEST_CODE_PHOTO = 0x1113;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_customized_view);
rim = (frameLayout) findViewById(R.id.rim);
//1. Obtain the screen density to calculate the viewfinder's rectangle.
DisplayMetrics dm = getResources().getDisplayMetrics();
float density = dm.density;
//2. Obtain the screen size.
mScreenWidth = getResources().getDisplayMetrics().widthPixels;
mScreenHeight = getResources().getDisplayMetrics().heightPixels;
int scanframeSize = (int) (SCAN_frame_SIZE * density);
//3. Calculate the viewfinder's rectangle, which in the middle of the layout.
//Set the scanning area. (Optional. Rect can be null. If no settings are specified, it will be located in the middle of the layout.)
Rect rect = new Rect();
rect.left = mScreenWidth / 2 - scanframeSize / 2;
rect.right = mScreenWidth / 2 + scanframeSize / 2;
rect.top = mScreenHeight / 2 - scanframeSize / 2;
rect.bottom = mScreenHeight / 2 + scanframeSize / 2;
//Initialize the RemoteView instance, and set callback for the scanning result.
remoteView = new RemoteView.Builder().setContext(this).setBoundingBox(rect).setFormat(HmsScan.ALL_SCAN_TYPE).build();
// Subscribe to the scanning result callback event.
remoteView.setonResultCallback(new onResultCallback() {
@Override
public void onResult(HmsScan[] result) {
//Check the result.
if (result != null && result.length > 0 && result[0] != null && !TextUtils.isEmpty(result[0].getOriginalValue())) {
Intent intent = new Intent();
intent.putExtra(SCAN_RESULT, result[0]);
setResult(RESULT_OK, intent);
CustomizedViewActivity.this.finish();
}
}
});
// Load the customized view to the activity.
remoteView.onCreate(savedInstanceState);
frameLayout.LayoutParams params = new frameLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT);
rim.addView(remoteView, params);
}
@Override
protected void onStart() {
super.onStart();
remoteView.onStart();
}
@Override
protected void onResume() {
super.onResume();
remoteView.onResume();
}
@Override
protected void onPause() {
super.onPause();
remoteView.onPause();
}
@Override
protected void onDestroy() {
super.onDestroy();
remoteView.onDestroy();
}
@Override
protected void onStop() {
super.onStop();
remoteView.onStop();
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK && requestCode == REQUEST_CODE_PHOTO) {
try {
Bitmap bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), data.getData());
HmsScan[] hmsScans = ScanUtil.decodeWithBitmap(CustomizedViewActivity.this, bitmap, new HmsScanAnalyzerOptions.Creator().setPhotoMode(true).create());
if (hmsScans != null && hmsScans.length > 0 && hmsScans[0] != null && !TextUtils.isEmpty(hmsScans[0].getOriginalValue())) {
Intent intent = new Intent();
intent.putExtra(SCAN_RESULT, hmsScans[0]);
setResult(RESULT_OK, intent);
CustomizedViewActivity.this.finish();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
自定义view ---->ViewfinderView.java
使用的是XZing当中的view效果
package com.iqos.qrscanner.widget;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.View;
import com.iqos.qrscanner.R;
import com.iqos.qrscanner.utils.BitmapUtil;
public final class ViewfinderView extends View {
private static final long ANIMATION_DELAY = 1L;//刷新界面的时间
private static final int DEFAULT_CORNER_WIDTH = 1;//四个绿色边角对应的宽度
private static final int DEFAULT_CORNER_LENGTH = 30;//四个绿色边角对应的长度
private static final int DEFAULT_MOVE_SPEED = 5;//中间那条线每次刷新移动的距离
private static final int DEFAULT_TIP_TEXT_SIZE = 14;//默认字体大小
private static final int DEFAULT_SCAN_RES_RECT_WIDTH = 18;//扫描线的粗细
private static final int DEFAULT_TXT_PADDING_RECT = 10;//文本与取景框间距(默认值)
private Paint mPaint = new Paint();//画笔对象的引用
private int slideTop;//中间滑动线的最顶端位置
private boolean tipAboveRect;//文本在上?
private boolean isFirst;
private int tipTextSize;//扫码文本字体大小
private int scanLineColor;//扫描的线的颜色
private int cornerColor;//角的颜色
private int cornerWidth;//角的宽度
private int cornerLength;//角的长
private int textPaddingRect;//文本与取景框间距
private int scanLineRes;//扫描线的资源id
private int lineMoveSpeed;//扫描线移动速度
private String tipText;//显示文本
private String scanViewTitle;//扫码界面的Title
private Context context;
private static final String TAG = "ViewfinderView";
private Point screenResolution;
private Rect framingRect;
public ViewfinderView(Context context, AttributeSet attrs) {
super(context, attrs);
Log.e(TAG, "ViewfinderView: 进入: " );
this.context = context;
this.initialAttrs(attrs);
}
private void initialAttrs(AttributeSet attrs) {
TypedArray td = context.obtainStyledAttributes(attrs, R.styleable.ViewfinderView);
//----------------------------------提示文本--------------------------------------------
tipText = td.getString(R.styleable.ViewfinderView_scan_tip_text);
//----------------------------------文本是否处于扫描框的上方--------------------------------
tipAboveRect = td.getBoolean(R.styleable.ViewfinderView_scan_text_above_rect, false);
//----------------------------------提示文本与扫描框的距离---------------------------------
textPaddingRect = td.getDimensionPixelSize(R.styleable.ViewfinderView_scan_text_padding_rect, DEFAULT_TXT_PADDING_RECT);
//----------------------------------提示文本大小---------------------------------------
tipTextSize = td.getDimensionPixelSize(R.styleable.ViewfinderView_scan_tip_text_size, DEFAULT_TIP_TEXT_SIZE);
//----------------------------------角的长度---------------------------------------------
cornerLength = td.getDimensionPixelSize(R.styleable.ViewfinderView_scan_rect_corner_length, DEFAULT_CORNER_LENGTH);
//----------------------------------角的颜色---------------------------------------------
cornerColor = td.getColor(R.styleable.ViewfinderView_scan_rect_corner_color, Color.GREEN);
//----------------------------------扫描的线的颜色---------------------------------------------
scanLineColor = td.getColor(R.styleable.ViewfinderView_scan_rect_corner_color, Color.GREEN);
//----------------------------------角宽-----------------------------------------------
cornerWidth = td.getDimensionPixelOffset(R.styleable.ViewfinderView_scan_rect_corner_width, DEFAULT_CORNER_WIDTH);
//----------------------------------扫描线---------------------------------------------
scanLineRes = td.getResourceId(R.styleable.ViewfinderView_scan_line_res, -1);
//----------------------------------扫描界面的Title---------------------------------------------
scanViewTitle = td.getString(R.styleable.ViewfinderView_scan_view_title_text);
//----------------------------------扫描线移动速度--------------------------------------
lineMoveSpeed = td.getInteger(R.styleable.ViewfinderView_scan_line_move_speed, DEFAULT_MOVE_SPEED);
lineMoveSpeed = lineMoveSpeed > DEFAULT_MOVE_SPEED ? DEFAULT_MOVE_SPEED : lineMoveSpeed;
td.recycle();
}
@SuppressLint("DrawAllocation")
@Override
public void onDraw(Canvas canvas) {
DisplayMetrics dm = context.getResources().getDisplayMetrics();
int screenWidth = dm.widthPixels;
int screenHeight = dm.heightPixels;
screenResolution = new Point(screenWidth, screenHeight);
int mWidth = screenResolution.x * 2 / 3;
int mHeight = screenResolution.x * 2 / 3;
int leftOffset = (screenResolution.x - mWidth) >> 1;
int topOffset = (screenResolution.y - mHeight) >> 2;
framingRect = new Rect(leftOffset, topOffset, leftOffset + mWidth, topOffset + mHeight);
//初始化中间线滑动的最上边和最下边
if (!isFirst) {
isFirst = true;
slideTop = framingRect.top;
}
//获取屏幕的宽和高
int width = getWidth();
int height = getHeight();
//画出扫描框外面的阴影部分,共四个部分,扫描框的上面到屏幕上面,扫描框的下面到屏幕下面
//扫描框的左边面到屏幕左边,扫描框的右边到屏幕右边
mPaint.setAlpha(0x40);
canvas.drawRect(0, 0, width, framingRect.top, mPaint);
canvas.drawRect(0, framingRect.top, framingRect.left, framingRect.bottom + 1, mPaint);
canvas.drawRect(framingRect.right + 1, framingRect.top, width, framingRect.bottom + 1, mPaint);
canvas.drawRect(0, framingRect.bottom + 1, width, height, mPaint);
//画扫描框边上的角,总共8个部分
mPaint.setAlpha(0xff);
mPaint.setColor(cornerColor);
canvas.drawRect(framingRect.left, framingRect.top, framingRect.left + cornerLength, framingRect.top + cornerWidth, mPaint);
canvas.drawRect(framingRect.left, framingRect.top, framingRect.left + cornerWidth, framingRect.top + cornerLength, mPaint);
canvas.drawRect(framingRect.right - cornerLength, framingRect.top, framingRect.right, framingRect.top + cornerWidth, mPaint);
canvas.drawRect(framingRect.right - cornerWidth, framingRect.top, framingRect.right, framingRect.top + cornerLength, mPaint);
canvas.drawRect(framingRect.left, framingRect.bottom - cornerWidth, framingRect.left + cornerLength, framingRect.bottom, mPaint);
canvas.drawRect(framingRect.left, framingRect.bottom - cornerLength, framingRect.left + cornerWidth, framingRect.bottom, mPaint);
canvas.drawRect(framingRect.right - cornerLength, framingRect.bottom - cornerWidth, framingRect.right, framingRect.bottom, mPaint);
canvas.drawRect(framingRect.right - cornerWidth, framingRect.bottom - cornerLength, framingRect.right, framingRect.bottom, mPaint);
//---------------绘制中间的线,每次刷新界面,中间的线往下移动SPEED_DISTANCE---------------//
slideTop += lineMoveSpeed;
if (slideTop + DEFAULT_SCAN_RES_RECT_WIDTH >= framingRect.bottom) {
slideTop = framingRect.top;
}
Rect lineRect = new Rect();
lineRect.left = framingRect.left;
lineRect.right = framingRect.right;
lineRect.top = slideTop;
lineRect.bottom = slideTop + DEFAULT_SCAN_RES_RECT_WIDTH;
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), scanLineRes);
if (null == bitmap) {
bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.qr_code_scan_line);
bitmap = BitmapUtil.tintBitmap(bitmap, scanLineColor);
}
canvas.drawBitmap(bitmap, null, lineRect, mPaint);
//----------------------------画扫描框下面的字---------------------------------//
mPaint.setColor(Color.WHITE);
mPaint.setTextSize(tipTextSize);
mPaint.setTextAlign(Paint.Align.CENTER);
mPaint.setAntiAlias(true);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setTypeface(Typeface.create(ViewfinderView.class.getSimpleName(), Typeface.BOLD));
if (!TextUtils.isEmpty(tipText)) {
if (tipAboveRect) {
canvas.drawText(tipText, getWidth() >> 1, framingRect.top - textPaddingRect, mPaint);
} else {
Rect rect = new Rect();
mPaint.getTextBounds(tipText, 0, tipText.length(), rect);
canvas.drawText(tipText, getWidth() >> 1, framingRect.bottom + rect.height() + textPaddingRect, mPaint);
}
}
//只刷新扫描框的内容,其他地方不刷新
postInvalidateDelayed(ANIMATION_DELAY, framingRect.left, framingRect.top, framingRect.right, framingRect.bottom);
}
public String getScanViewTitle() {
return TextUtils.isEmpty(scanViewTitle) ? "扫描二维码" : scanViewTitle;
}
public void drawViewfinder() {
invalidate();
}
}
attrs.xml
自定义属性
到此完成!



