Android集成zxing掃碼框架功能
我們知道zxing是一個(gè)強(qiáng)大的處理二維碼和條形碼等的開源庫(kù),本篇文章記錄一下自己在項(xiàng)目中集成zxing開源庫(kù)的過(guò)程。
導(dǎo)入依賴
implementation 'com.google.zxing:core:3.3.3'
申請(qǐng)權(quán)限
在AndroidManifest中申請(qǐng)相應(yīng)權(quán)限:
<!--相機(jī)--> <uses-permission android:name="android.permission.CAMERA" /> <!--震動(dòng)--> <uses-permission android:name="android.permission.VIBRATE" /> <!--存儲(chǔ)--> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
導(dǎo)入相關(guān)代碼和資源文件
導(dǎo)入的代碼文件如下(源碼在末尾):

相關(guān)的資源文件:
1、在res/values下新建ids.xml文件,引入下面id:
<!--二維碼/條形碼掃描相關(guān)--> <item name="auto_focus" type="id" /> <item name="decode" type="id" /> <item name="decode_failed" type="id" /> <item name="decode_succeeded" type="id" /> <item name="encode_failed" type="id" /> <item name="encode_succeeded" type="id" /> <item name="launch_product_query" type="id" /> <item name="quit" type="id" /> <item name="restart_preview" type="id" /> <item name="return_scan_result" type="id" /> <item name="search_book_contents_failed" type="id" /> <item name="search_book_contents_succeeded" type="id" />
2、在res/values下新建attrs.xml文件,加入掃碼框的屬性,主要是ViewfinderView在使用:
<!--掃碼框?qū)傩?-> <declare-styleable name="ViewfinderView"> <attr name="corner_color" format="color" /> <attr name="corner_size" format="dimension" /> <attr name="corner_stroke_width" format="dimension" /> <attr name="corner_position" format="enum"> <enum name="inside" value="1" /> <enum name="outside" value="2" /> </attr> <attr name="line_color" format="color" /> <attr name="line_height" format="dimension" /> <attr name="line_move_distance" format="dimension" /> <attr name="frame_width" format="dimension" /> <attr name="frame_height" format="dimension" /> <attr name="frame_centerX" format="dimension" /> <attr name="frame_centerY" format="dimension" /> <attr name="frame_color" format="color" /> <attr name="frame_stroke_width" format="dimension" /> <attr name="mask_color" format="color" /> <attr name="result_point_color" format="color" /> <attr name="label_text" format="string" /> <attr name="label_text_color" format="color" /> <attr name="label_text_size" format="dimension" /> <attr name="label_text_margin" format="dimension" /> </declare-styleable>
3、在res下新建raw目錄,導(dǎo)入beep.mp3,實(shí)現(xiàn)掃碼成功的滴滴音效,BeepManager在使用
上面是一些比較重要的資源。
然后介紹一下幾個(gè)主要的類:
1、ViewfinderView:自定義掃描框,代碼如下,因?yàn)橛凶⑨?,就不多說(shuō)明了。
public final class ViewfinderView extends View {
private static final long ANIMATION_DELAY = 10L;
private static final int OPAQUE = 1;
private static final int CORNER_INSIDE = 1; //四個(gè)邊角在掃描區(qū)內(nèi)
private static final int CORNER_OUTSIDE = 2; //四個(gè)邊角在掃描區(qū)外
private Paint paint;
//掃描區(qū)四個(gè)邊角的顏色
private int cornerColor;
//掃描區(qū)邊角的大小
private float cornerSize;
//掃描區(qū)邊角的寬度
private float cornerStrokeWidth;
//邊角的方向,在掃描區(qū)域內(nèi)還是掃描區(qū)域外
private int cornerPosition;
//掃描線顏色
private int lineColor;
//掃描線高度
private float lineHeight;
//掃描線移動(dòng)距離
private float lineMoveDistance;
//掃描區(qū)域?qū)挾榷?
private float frameWidth;
//掃描區(qū)域高度
private float frameHeight;
//掃描區(qū)域中心位置的X坐標(biāo),默認(rèn)正中間,在onLayout中設(shè)置
private float frameCenterX;
//掃描區(qū)域中心位置的Y坐標(biāo),默認(rèn)正中間,在onLayout中設(shè)置
private float frameCenterY;
//掃描區(qū)域邊框顏色
private int frameColor;
//掃描區(qū)域邊框?qū)挾?
private float frameStrokeWidth;
//模糊區(qū)域顏色
private int maskColor;
//掃描點(diǎn)的顏色
private int resultPointColor;
//掃描區(qū)域提示文本
private String labelText;
//掃描區(qū)域提示文本顏色
private int labelTextColor;
//掃描區(qū)域提示文本字體大小
private float labelTextSize;
//掃描區(qū)域提示文本的邊距
private float labelTextMargin;
public static int scannerStart = 0;
public static int scannerEnd = 0;
private Collection<ResultPoint> possibleResultPoints;
private Collection<ResultPoint> lastPossibleResultPoints;
// This constructor is used when the class is built from an XML resource.
public ViewfinderView(Context context, AttributeSet attrs) {
super(context, attrs);
//初始化自定義屬性信息
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.ViewfinderView);
cornerColor = ta.getColor(R.styleable.ViewfinderView_corner_color, getResources().getColor(R.color.colorPrimary));
cornerSize = ta.getDimension(R.styleable.ViewfinderView_corner_size, dp2px(context, 28));
cornerStrokeWidth = ta.getDimension(R.styleable.ViewfinderView_corner_stroke_width, dp2px(context, 4));
cornerPosition = ta.getInt(R.styleable.ViewfinderView_corner_position, CORNER_INSIDE);
lineColor = ta.getColor(R.styleable.ViewfinderView_line_color, getResources().getColor(R.color.colorPrimary));
lineHeight = ta.getDimension(R.styleable.ViewfinderView_line_height, dp2px(context, 3));
lineMoveDistance = ta.getDimension(R.styleable.ViewfinderView_line_move_distance, dp2px(context, 2));
frameWidth = ta.getDimension(R.styleable.ViewfinderView_frame_width, dp2px(context, 220));
frameHeight = ta.getDimension(R.styleable.ViewfinderView_frame_height, dp2px(context, 220));
frameCenterX = ta.getDimension(R.styleable.ViewfinderView_frame_centerX, -1);
frameCenterY = ta.getDimension(R.styleable.ViewfinderView_frame_centerY, -1);
frameColor = ta.getColor(R.styleable.ViewfinderView_frame_color, Color.parseColor("#90FFFFFF"));
frameStrokeWidth = ta.getDimension(R.styleable.ViewfinderView_frame_stroke_width, dp2px(context, 0.2f));
maskColor = ta.getColor(R.styleable.ViewfinderView_mask_color, Color.parseColor("#60000000"));
resultPointColor = ta.getColor(R.styleable.ViewfinderView_result_point_color, Color.TRANSPARENT);
labelText = ta.getString(R.styleable.ViewfinderView_label_text);
labelTextColor = ta.getColor(R.styleable.ViewfinderView_label_text_color, Color.WHITE);
labelTextSize = ta.getDimension(R.styleable.ViewfinderView_label_text_size, sp2px(context, 15));
labelTextMargin = ta.getDimension(R.styleable.ViewfinderView_label_text_margin, dp2px(context, 18));
ta.recycle();
paint = new Paint();
paint.setAntiAlias(true);
possibleResultPoints = new HashSet<ResultPoint>(5);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
//如果沒(méi)有設(shè)置frameCenterX和frameCenterY默認(rèn)布局正中間的X、Y坐標(biāo)
frameCenterX = (frameCenterX == -1) ? getWidth() / 2f : frameCenterX;
frameCenterY = (frameCenterY == -1) ? getHeight() / 2f : frameCenterY;
//設(shè)置掃描區(qū)域位置
int leftOffset = (int) (frameCenterX - frameWidth / 2f);
int topOffset = (int) (frameCenterY - frameHeight / 2f);
//設(shè)置掃描區(qū)不超過(guò)屏幕
leftOffset = leftOffset > 0 ? leftOffset : 0;
topOffset = topOffset > 0 ? topOffset : 0;
Rect rect = new Rect();
rect.left = leftOffset;
rect.top = topOffset;
rect.right = (int) (leftOffset + frameWidth);
rect.bottom = (int) (topOffset + frameHeight);
CameraManager.get().setFramingRect(rect);
}
@Override
public void onDraw(Canvas canvas) {
Rect frame = CameraManager.get().getFramingRect();
if (frame == null) {
return;
}
if (scannerStart == 0 || scannerEnd == 0) {
scannerStart = frame.top;
scannerEnd = frame.bottom;
}
int width = canvas.getWidth();
int height = canvas.getHeight();
//繪制模糊區(qū)域
drawExterior(canvas, frame, width, height);
//繪制掃描區(qū)邊框
drawFrame(canvas, frame);
//繪制邊角
drawCorner(canvas, frame);
//繪制提示信息
drawTextInfo(canvas, frame);
//繪制掃描線
drawScanLine(canvas, frame);
//繪制閃爍點(diǎn)
drawResultPoint(canvas, frame);
// Request another update at the animation interval, but only repaint the laser line,
// not the entire viewfinder mask.
//指定重繪區(qū)域,該方法會(huì)在子線程中執(zhí)行
postInvalidateDelayed(ANIMATION_DELAY, frame.left, frame.top, frame.right, frame.bottom);
}
// 繪制模糊區(qū)域 Draw the exterior (i.e. outside the framing rect) darkened
private void drawExterior(Canvas canvas, Rect frame, int width, int height) {
paint.setColor(maskColor);
canvas.drawRect(0, 0, width, frame.top, paint);
canvas.drawRect(0, frame.top, frame.left, frame.bottom, paint);
canvas.drawRect(frame.right, frame.top, width, frame.bottom, paint);
canvas.drawRect(0, frame.bottom, width, height, paint);
}
// 繪制掃描區(qū)邊框 Draw a two pixel solid black border inside the framing rect
private void drawFrame(Canvas canvas, Rect frame) {
if (frameStrokeWidth > 0) {
paint.setColor(frameColor);
if (cornerPosition == CORNER_INSIDE) { //邊角在掃描區(qū)內(nèi)
//左邊
canvas.drawRect(frame.left, frame.top, frame.left + frameStrokeWidth, frame.bottom, paint);
//上邊
canvas.drawRect(frame.left, frame.top, frame.right, frame.top + frameStrokeWidth, paint);
//右邊
canvas.drawRect(frame.right - frameStrokeWidth, frame.top, frame.right, frame.bottom, paint);
//下邊
canvas.drawRect(frame.left, frame.bottom - frameStrokeWidth, frame.right, frame.bottom, paint);
} else { //邊角在掃描區(qū)外
//左邊
canvas.drawRect(frame.left - frameStrokeWidth, frame.top - frameStrokeWidth,
frame.left, frame.bottom + frameStrokeWidth, paint);
//上邊
canvas.drawRect(frame.left - frameStrokeWidth, frame.top - frameStrokeWidth,
frame.right + frameStrokeWidth, frame.top, paint);
//右邊
canvas.drawRect(frame.right, frame.top - frameStrokeWidth, frame.right + frameStrokeWidth,
frame.bottom + frameStrokeWidth, paint);
//下邊
canvas.drawRect(frame.left - frameStrokeWidth, frame.bottom, frame.right + frameStrokeWidth,
frame.bottom + frameStrokeWidth, paint);
}
}
}
//繪制邊角
private void drawCorner(Canvas canvas, Rect frame) {
if (cornerSize > 0 && cornerStrokeWidth > 0) {
paint.setColor(cornerColor);
if (cornerPosition == CORNER_INSIDE) { //繪制在掃描區(qū)域內(nèi)區(qū)
//左上
canvas.drawRect(frame.left, frame.top, frame.left + cornerSize, frame.top + cornerStrokeWidth, paint);
canvas.drawRect(frame.left, frame.top, frame.left + cornerStrokeWidth, frame.top + cornerSize, paint);
//右上
canvas.drawRect(frame.right - cornerSize, frame.top, frame.right, frame.top + cornerStrokeWidth, paint);
canvas.drawRect(frame.right - cornerStrokeWidth, frame.top, frame.right, frame.top + cornerSize, paint);
//左下
canvas.drawRect(frame.left, frame.bottom - cornerSize, frame.left + cornerStrokeWidth, frame.bottom, paint);
canvas.drawRect(frame.left, frame.bottom - cornerStrokeWidth, frame.left + cornerSize, frame.bottom, paint);
//右下
canvas.drawRect(frame.right - cornerSize, frame.bottom - cornerStrokeWidth, frame.right, frame.bottom, paint);
canvas.drawRect(frame.right - cornerStrokeWidth, frame.bottom - cornerSize, frame.right, frame.bottom, paint);
} else { //繪制在掃描區(qū)域外區(qū)
//左上
canvas.drawRect(frame.left - cornerStrokeWidth, frame.top - cornerStrokeWidth,
frame.left - cornerStrokeWidth + cornerSize, frame.top, paint);
canvas.drawRect(frame.left - cornerStrokeWidth, frame.top - cornerStrokeWidth,
frame.left, frame.top - cornerStrokeWidth + cornerSize, paint);
//右上
canvas.drawRect(frame.right + cornerStrokeWidth - cornerSize, frame.top - cornerStrokeWidth,
frame.right + cornerStrokeWidth, frame.top, paint);
canvas.drawRect(frame.right, frame.top - cornerStrokeWidth,
frame.right + cornerStrokeWidth, frame.top - cornerStrokeWidth + cornerSize, paint);
//左下
canvas.drawRect(frame.left - cornerStrokeWidth, frame.bottom, frame.left - cornerStrokeWidth + cornerSize,
frame.bottom + cornerStrokeWidth, paint);
canvas.drawRect(frame.left - cornerStrokeWidth, frame.bottom + cornerStrokeWidth - cornerSize,
frame.left, frame.bottom + cornerStrokeWidth, paint);
//右下
canvas.drawRect(frame.right + cornerStrokeWidth - cornerSize, frame.bottom,
frame.right + cornerStrokeWidth, frame.bottom + cornerStrokeWidth, paint);
canvas.drawRect(frame.right, frame.bottom + cornerStrokeWidth - cornerSize,
frame.right + cornerStrokeWidth, frame.bottom + cornerStrokeWidth, paint);
}
}
}
//繪制文本
private void drawTextInfo(Canvas canvas, Rect frame) {
if (!TextUtils.isEmpty(labelText)) {
paint.setColor(labelTextColor);
paint.setTextSize(labelTextSize);
paint.setTextAlign(Paint.Align.CENTER);
Paint.FontMetrics fm = paint.getFontMetrics();
float baseY = frame.bottom + labelTextMargin - fm.ascent;
canvas.drawText(labelText, frame.left + frame.width() / 2, baseY, paint);
}
}
//繪制掃描線
private void drawScanLine(Canvas canvas, Rect frame) {
if (lineHeight > 0) {
paint.setColor(lineColor);
RadialGradient radialGradient = new RadialGradient(
(float) (frame.left + frame.width() / 2),
(float) (scannerStart + lineHeight / 2),
360f,
lineColor,
shadeColor(lineColor),
Shader.TileMode.MIRROR);
paint.setShader(radialGradient);
if (scannerStart <= scannerEnd) {
//橢圓
RectF rectF = new RectF(frame.left + 2 * lineHeight, scannerStart, frame.right - 2 * lineHeight,
scannerStart + lineHeight);
canvas.drawOval(rectF, paint);
scannerStart += lineMoveDistance;
} else {
scannerStart = frame.top;
}
paint.setShader(null);
}
}
private void drawResultPoint(Canvas canvas, Rect frame) {
if (resultPointColor != Color.TRANSPARENT) {
Collection<ResultPoint> currentPossible = possibleResultPoints;
Collection<ResultPoint> currentLast = lastPossibleResultPoints;
if (currentPossible.isEmpty()) {
lastPossibleResultPoints = null;
} else {
possibleResultPoints = new HashSet<ResultPoint>(5);
lastPossibleResultPoints = currentPossible;
paint.setAlpha(OPAQUE);
paint.setColor(resultPointColor);
for (ResultPoint point : currentPossible) {
canvas.drawCircle(frame.left + point.getX(), frame.top + point.getY(), 6.0f, paint);
}
}
if (currentLast != null) {
paint.setAlpha(OPAQUE / 2);
paint.setColor(resultPointColor);
for (ResultPoint point : currentLast) {
canvas.drawCircle(frame.left + point.getX(), frame.top + point.getY(), 3.0f, paint);
}
}
}
}
//處理顏色模糊
public int shadeColor(int color) {
String hax = Integer.toHexString(color);
String result = "20" + hax.substring(2);
return Integer.valueOf(result, 16);
}
public void drawViewfinder() {
invalidate();
}
public void addPossibleResultPoint(ResultPoint point) {
possibleResultPoints.add(point);
}
private int dp2px(Context context, float dpValue) {
float density = context.getApplicationContext().getResources().getDisplayMetrics().density;
return (int) (dpValue * density + 0.5f);
}
private int sp2px(Context context, float spValue) {
float scaleDensity = context.getApplicationContext().getResources().getDisplayMetrics().scaledDensity;
return (int) (spValue * scaleDensity + 0.5f);
}
}
2、CaptureActivity:掃碼的Activity基類,代碼如下;
/**
* Created by xuzhb on 2019/11/16
* Desc:掃碼的Activity類
* 整個(gè)Activity最重要的兩個(gè)控件是一個(gè)SurfaceView(攝像頭)和一個(gè)ViewfinderView(掃描區(qū))
* 對(duì)于繼承CaptureActivity的Activity子類來(lái)說(shuō),
* 可以選擇在自己的布局中定義和CaptureActivity的布局文件id相同的控件,
* 這樣即使它們?cè)趦蓚€(gè)布局中表現(xiàn)不同也能執(zhí)行相同的邏輯,包括其他控件
* 或者選擇重寫getSurfaceView()和getViewfinderView()返回對(duì)應(yīng)的兩個(gè)控件,
* 掃碼最終是在handleDecode(Result result, Bitmap bitmap)處理掃描后的結(jié)果
*/
public class CaptureActivity extends AppCompatActivity implements SurfaceHolder.Callback {
private static final String TAG = "CaptureActivity";
private static final int IMAGE_PICKER = 1999;
private BeepManager mBeepManager;
private CaptureActivityHandler mHandler;
private Vector<BarcodeFormat> mDecodeFormats;
private String mCharacterSet;
private InactivityTimer mInactivityTimer;
private boolean hasSurface = false;
private boolean isLightOn = false; //是否打開閃光燈
private boolean isPlayBeep = true; //是否開啟掃描后的滴滴聲
private boolean isVibrate = true; //是否震動(dòng)
private String mPhotoPath; //選中的圖片路徑
private TitleBar mTitleBar;
private SurfaceView mSurfaceView;
private ViewfinderView mViewfinderView;
private LinearLayout mLightLl;
private ImageView mLightIv;
private TextView mLightTv;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(getLayoutId());
CameraManager.init(getApplicationContext());
mBeepManager = new BeepManager(this);
hasSurface = false;
mInactivityTimer = new InactivityTimer(this);
handleView(savedInstanceState);
initView();
initListener();
}
protected int getLayoutId() {
return R.layout.activity_capture;
}
protected void handleView(@Nullable Bundle savedInstanceState) {
}
private void initView() {
mTitleBar = findViewById(R.id.title_bar);
mSurfaceView = findViewById(R.id.surfaceView);
mViewfinderView = findViewById(R.id.viewfinderView);
mLightLl = findViewById(R.id.light_ll);
mLightIv = findViewById(R.id.light_iv);
mLightTv = findViewById(R.id.light_tv);
}
protected void initListener() {
//因?yàn)槔^承CaptureActivity的Activity子類的布局不一定包含id為title_bar和light_ll的控件,
//沒(méi)有的話如果子類通過(guò)super.initListener()覆寫時(shí)會(huì)因?yàn)檎也坏蕉鴪?bào)異常,所以這里加了一個(gè)判空;
//如果子類的布局中包含id相同的控件,則不需要在子類中再重寫相同的邏輯
if (mTitleBar != null) {
StatusBarUtil.INSTANCE.darkModeAndPadding(this, mTitleBar, Color.BLACK, 0, false);
mTitleBar.setOnLeftClickListener(v -> {
finish();
return null;
});
mTitleBar.setOnRightClickListener(v -> {
openAlbum(); //打開相冊(cè)選取圖片掃描
return null;
});
}
if (mLightLl != null) {
mLightLl.setOnClickListener(v -> switchLight()); //打開或關(guān)閉閃光燈
}
}
//打開相冊(cè)
protected void openAlbum() {
Intent intent = new Intent(Intent.ACTION_PICK, null);
intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");
startActivityForResult(intent, IMAGE_PICKER);
}
//開啟/關(guān)閉閃光燈
private void switchLight() {
if (CameraManager.get() != null) {
if (isLightOn) {
mLightTv.setText("輕觸點(diǎn)亮");
CameraManager.get().turnLightOffFlashLight();
} else {
mLightTv.setText("輕觸關(guān)閉");
CameraManager.get().turnOnFlashLight();
}
isLightOn = !isLightOn;
mLightIv.setSelected(isLightOn);
}
}
@Override
protected void onResume() {
super.onResume();
SurfaceHolder holder = getSurfaceView().getHolder();
if (hasSurface) {
initCamera(holder);
} else {
holder.addCallback(this);
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
mDecodeFormats = null;
mCharacterSet = null;
}
@Override
protected void onPause() {
super.onPause();
if (mHandler != null) {
mHandler.quitSynchronously();
mHandler = null;
}
CameraManager.get().closeDriver();
}
@Override
protected void onDestroy() {
mInactivityTimer.shutdown();
mBeepManager.releaseRing();
super.onDestroy();
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
if (!hasSurface) {
hasSurface = true;
initCamera(holder);
}
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
hasSurface = false;
}
private void initCamera(SurfaceHolder holder) {
try {
CameraManager.get().openDriver(holder);
} catch (Exception e) {
e.printStackTrace();
}
if (mHandler == null) {
mHandler = new CaptureActivityHandler(this, mDecodeFormats, mCharacterSet);
}
}
//繼承CaptureActivity的Activity類,如果SurfaceView的id和CaptureActivity布局中SurfaceView的id不同
//需要重寫這個(gè)方法,返回自己布局中的SurfaceView
public SurfaceView getSurfaceView() {
return mSurfaceView;
}
//繼承CaptureActivity的Activity類,如果ViewfinderView的id和CaptureActivity布局中ViewfinderView的id不同
//需要重寫這個(gè)方法,返回自己布局中的ViewfinderView
public ViewfinderView getViewfinderView() {
return mViewfinderView;
}
public Handler getHandler() {
return mHandler;
}
public void drawViewfinder() {
getViewfinderView().drawViewfinder();
}
//處理掃描后的結(jié)果
public void handleDecode(Result result, Bitmap bitmap) {
mInactivityTimer.onActivity();
if (result != null) {
String text = result.getText();
Log.i(TAG, "識(shí)別的結(jié)果:" + text);
if (!TextUtils.isEmpty(text)) { //識(shí)別成功
playBeepSoundAndVibrate();
returnQRCodeResult(text);
} else {
showToast("很抱歉,識(shí)別二維碼失敗!");
}
} else {
showToast("未發(fā)現(xiàn)二維碼!");
}
}
private void playBeepSoundAndVibrate() {
if (isPlayBeep) {
mBeepManager.startRing(); //播放掃碼的滴滴聲
}
if (isVibrate) {
Vibrator vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
if (vibrator != null) {
vibrator.vibrate(200); //震動(dòng)200毫秒
}
}
}
//返回掃描結(jié)果
private void returnQRCodeResult(String result) {
Intent intent = new Intent();
intent.putExtra(QRConstant.SCAN_QRCODE_RESULT, result);
setResult(Activity.RESULT_OK, intent);
finish();
}
private void showToast(CharSequence text) {
runOnUiThread(() -> {
ToastUtil.INSTANCE.showToast(text, true, false, getApplicationContext());
});
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == IMAGE_PICKER && resultCode == Activity.RESULT_OK) {
if (data != null) {
Uri uri = data.getData();
if (uri != null) {
Cursor cursor = getContentResolver().query(uri, null, null, null, null);
if (cursor != null) {
if (cursor.moveToFirst()) {
mPhotoPath = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
}
cursor.close();
if (!TextUtils.isEmpty(mPhotoPath)) {
//可以加個(gè)提示正在掃描的加載框,如showLoadingDialog("正在掃描...")
new Thread(() -> {
handleDecode(QRCodeUtil.decodeImage(mPhotoPath), null);
//取消加載框,dismissLoadingDialog()
}).start();
} else {
Log.e(TAG, "未找到圖片");
}
}
}
}
}
}
}
看一下使用的例子

最后,附上整個(gè)項(xiàng)目的github地址,注:項(xiàng)目使用了視圖綁定ViewBinding,所以需要使用AndroidStudio 3.6.x版本。
到此這篇關(guān)于Android集成zxing掃碼框架功能的文章就介紹到這了,更多相關(guān)android zxing掃碼內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Android實(shí)現(xiàn)讀取掃碼槍內(nèi)容(條形碼)
- android讀取掃碼模組數(shù)據(jù)的方法
- Android實(shí)現(xiàn)USB掃碼槍獲取掃描內(nèi)容
- Android接入U(xiǎn)SB掃碼模塊的方法
- Android 掃碼槍不使用輸入框獲取掃描值的操作方法
- Android實(shí)現(xiàn)掃碼功能
- Android 超簡(jiǎn)易Zxing框架 生成二維碼+掃碼功能
- Android手機(jī)(設(shè)備)連接掃描槍掃碼遇到的問(wèn)題
- Android設(shè)備獲取掃碼槍掃描的內(nèi)容與可能遇到的問(wèn)題解決
- Android設(shè)備獲取掃碼槍掃描內(nèi)容
相關(guān)文章
Android自定義view實(shí)現(xiàn)TextView方形輸入框
這篇文章主要為大家詳細(xì)介紹了Android自定義view實(shí)現(xiàn)TextView方形輸入框,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-06-06
android之json數(shù)據(jù)過(guò)長(zhǎng)打印不全問(wèn)題的解決
這篇文章主要介紹了android之json數(shù)據(jù)過(guò)長(zhǎng)打印不全問(wèn)題的解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-04-04
Android 配置gradle實(shí)現(xiàn)VersionCode自增實(shí)例
今天小編就為大家分享一篇Android 配置gradle實(shí)現(xiàn)VersionCode自增實(shí)例,具有很好的 參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-03-03
Android View滑動(dòng)的實(shí)現(xiàn)分析示例
View滑動(dòng)是Android實(shí)現(xiàn)自定義控件的基礎(chǔ),同時(shí)在開發(fā)中難免會(huì)遇到View的滑動(dòng)處理,其實(shí)不管是那種滑動(dòng)方法,基本思路是類似的;當(dāng)點(diǎn)擊事件傳到View時(shí),系統(tǒng)記下觸摸點(diǎn)的坐標(biāo),手指移動(dòng)時(shí)系統(tǒng)記下移動(dòng)后的左邊并算出偏移量,通過(guò)偏移量來(lái)修改View的坐標(biāo)2022-08-08
Android仿抖音右滑清屏左滑列表功能的實(shí)現(xiàn)代碼
這篇文章主要介紹了Android仿抖音右滑清屏左滑列表功能,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-06-06
Android自定義View app更新動(dòng)畫詳解
這篇文章給大家分享了Android自定義View app更新動(dòng)畫的相關(guān)代碼以及知識(shí)點(diǎn)內(nèi)容,有興趣的朋友參考學(xué)習(xí)下。2018-07-07
Android Studio生成函數(shù)注釋的實(shí)現(xiàn)方法
這篇文章主要介紹了Android Studio生成函數(shù)注釋的實(shí)現(xiàn)方法的相關(guān)資料,希望通過(guò)本文大家能夠?qū)崿F(xiàn)這樣的功能,需要的朋友可以參考下2017-09-09

