文档章节

自定义ZXing二维码扫描界面并解决取景框拉伸等问题

孤独的探索号
 孤独的探索号
发布于 2016/06/07 00:04
字数 1457
阅读 10K
收藏 98

先看效果

 

扫描内容是下面这张,二维码是用zxing库生成的

 

由于改了好几个类,还是去年的事都忘得差不多了,所以只能上这个类的代码了,主要就是改了这个CaptureActivity.java

 

package com.zxing.activity;

import java.io.IOException;
import java.util.Vector;

import android.app.Activity;
import android.content.Intent;
import android.content.res.AssetFileDescriptor;
import android.graphics.Bitmap;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.os.Handler;
import android.os.Vibrator;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;
import android.widget.Toast;

import com.ericssonlabs.R;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.Result;
import com.zxing.camera.CameraManager;
import com.zxing.decoding.CaptureActivityHandler;
import com.zxing.decoding.CaptureActivityHandler.DecodeCallback;
import com.zxing.decoding.InactivityTimer;
import com.zxing.view.ViewfinderView;
/**
 * Initial the camera
 * @author Ryan.Tang
 * @modifier Lemon
 * @use extends CaptureActivity并且在setContentView方法后调用init方法
 */
public abstract class CaptureActivity extends Activity implements Callback, DecodeCallback {
	//	private static final String TAG = "CaptureActivity";

	protected Activity context;
	protected SurfaceView surfaceView;
	protected ViewfinderView viewfinderView;
	/**初始化,必须在setContentView之后
	 * @param context
	 * @param viewfinderView
	 */
	protected void init(Activity context, SurfaceView surfaceView, ViewfinderView viewfinderView) {
		this.context = context;
		this.surfaceView = surfaceView;
		this.viewfinderView = viewfinderView;

		CameraManager.init(getApplication());

		hasSurface = false;
		inactivityTimer = new InactivityTimer(this);
	}


	private CaptureActivityHandler handler;
	private boolean hasSurface;
	private Vector<BarcodeFormat> decodeFormats;
	private String characterSet;
	private InactivityTimer inactivityTimer;
	private MediaPlayer mediaPlayer;
	private boolean playBeep;
	private static final float BEEP_VOLUME = 0.10f;
	private boolean vibrate;


	@Override
	protected void onResume() {
		super.onResume();
		SurfaceHolder surfaceHolder = surfaceView.getHolder();
		if (hasSurface) {
			initCamera(surfaceHolder);
		} else {
			surfaceHolder.addCallback(this);
			surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
		}
		decodeFormats = null;
		characterSet = null;

		playBeep = true;
		AudioManager audioService = (AudioManager) getSystemService(AUDIO_SERVICE);
		if (audioService.getRingerMode() != AudioManager.RINGER_MODE_NORMAL) {
			playBeep = false;
		}
		initBeepSound();
		vibrate = true;
	}

	@Override
	protected void onPause() {
		super.onPause();
		if (handler != null) {
			handler.quitSynchronously();
			handler = null;
		}
		CameraManager.get().closeDriver();
	}

	@Override
	protected void onDestroy() {
		inactivityTimer.shutdown();
		super.onDestroy();
	}


	public static final String RESULT_QRCODE_STRING = "RESULT_QRCODE_STRING";
	/**
	 * Handler scan result
	 * @param result
	 * @param barcode
	 */
	public void handleDecode(Result result, Bitmap barcode) {
		inactivityTimer.onActivity();
		playBeepSoundAndVibrate();
		String resultString = result.getText();
		//FIXME
		if (resultString.equals("")) {
			Toast.makeText(CaptureActivity.this, "Scan failed!", Toast.LENGTH_SHORT).show();
		}

		setResult(RESULT_OK, new Intent().putExtra(RESULT_QRCODE_STRING, resultString));
		finish();
	}

	private void initCamera(SurfaceHolder surfaceHolder) {
		try {
			CameraManager.get().openDriver(surfaceHolder);
		} catch (IOException ioe) {
			return;
		} catch (RuntimeException e) {
			return;
		}
		if (handler == null) {
			handler = new CaptureActivityHandler(this, decodeFormats,
					characterSet, viewfinderView, this);
		}
	}

	@Override
	public void drawViewfinder() {
		viewfinderView.drawViewfinder();		
	}


	@Override
	public void surfaceChanged(SurfaceHolder holder, int format, int width,
			int height) {

	}

	@Override
	public void surfaceCreated(SurfaceHolder holder) {
		if (!hasSurface) {
			hasSurface = true;
			initCamera(holder);
		}

	}

	@Override
	public void surfaceDestroyed(SurfaceHolder holder) {
		hasSurface = false;

	}


	public Handler getHandler() {
		return handler;
	}


	private void initBeepSound() {
		if (playBeep && mediaPlayer == null) {
			// The volume on STREAM_SYSTEM is not adjustable, and users found it
			// too loud,
			// so we now play on the music stream.
			setVolumeControlStream(AudioManager.STREAM_MUSIC);
			mediaPlayer = new MediaPlayer();
			mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
			mediaPlayer.setOnCompletionListener(beepListener);

			AssetFileDescriptor file = getResources().openRawResourceFd(
					R.raw.beep);
			try {
				mediaPlayer.setDataSource(file.getFileDescriptor(),
						file.getStartOffset(), file.getLength());
				file.close();
				mediaPlayer.setVolume(BEEP_VOLUME, BEEP_VOLUME);
				mediaPlayer.prepare();
			} catch (IOException e) {
				mediaPlayer = null;
			}
		}
	}

	private static final long VIBRATE_DURATION = 200L;

	private void playBeepSoundAndVibrate() {
		if (playBeep && mediaPlayer != null) {
			mediaPlayer.start();
		}
		if (vibrate) {
			Vibrator vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);
			vibrator.vibrate(VIBRATE_DURATION);
		}
	}

	/**
	 * When the beep has finished playing, rewind to queue up another one.
	 */
	private final OnCompletionListener beepListener = new OnCompletionListener() {
		public void onCompletion(MediaPlayer mediaPlayer) {
			mediaPlayer.seekTo(0);
		}
	};

}

使用方法: 新建一个Activity继承CaptureActivity并且在setContentView方法后调用init方法即可。
示例:

CameraScanActivity.java

package zuo.biao.activity;

import zuo.biao.R;
import zuo.biao.library.interfaces.OnBottomDragListener;
import zuo.biao.util.ActivityUtil;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnClickListener;

import com.zxing.activity.CaptureActivity;
import com.zxing.camera.CameraManager;
import com.zxing.view.ViewfinderView;

/**扫描二维码Activity
 * @author Lemon
 * @use 参考zuo.biao.library.ModelActivity
 */
public class CameraScanActivity extends CaptureActivity implements Callback, OnClickListener, OnBottomDragListener {
	public static final String TAG = ActivityUtil.TAG_CAMERA_SCAN_ACTIVITY;

	//启动方法<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

	/**启动这个Activity的Intent
	 * @param context
	 * @param title
	 * @return
	 */
	public static Intent createIntent(Context context) {
		return new Intent(context, CameraScanActivity.class);
	}

	//启动方法>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>



	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.camera_scan_activity);
		init(this, (SurfaceView) findViewById(R.id.svCameraScan), (ViewfinderView) findViewById(R.id.vfvCameraScan));

		//功能归类分区方法,必须调用<<<<<<<<<<
		initView();
		initData();
		initListener();
		//功能归类分区方法,必须调用>>>>>>>>>>

	}


	//UI显示区(操作UI,但不存在数据获取或处理代码,也不存在事件监听代码)<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

	public void initView() {//必须调用

	}



	//UI显示区(操作UI,但不存在数据获取或处理代码,也不存在事件监听代码)>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>










	//data数据区(存在数据获取或处理代码,但不存在事件监听代码)<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

	public void initData() {//必须调用

	}


	//data数据区(存在数据获取或处理代码,但不存在事件监听代码)>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>








	//listener事件监听区(只要存在事件监听代码就是)<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

	public void initListener() {//必须调用

		findViewById(R.id.tvCameraScanReturn).setOnClickListener(this);
		findViewById(R.id.ivCameraScanReturn).setOnClickListener(this);
		findViewById(R.id.ivCameraScanLight).setOnClickListener(this);
		findViewById(R.id.ivCameraScanMyQRCode).setOnClickListener(this);
	}

	//系统自带监听方法<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

	@Override
	public void onDragBottom(boolean rightToLeft) {
		if (rightToLeft) {

			return;
		}

		finish();
	}

	@Override
	public void onClick(View v) {
		switch (v.getId()) {
		case R.id.tvCameraScanReturn:
		case R.id.ivCameraScanReturn:
			onDragBottom(false);
			break;
		case R.id.ivCameraScanLight:
			switchLight(! isOpen);
			break;
		case R.id.ivCameraScanMyQRCode:
			//
			break;
		default:
			break;
		}
	}


	private boolean isOpen = false;
	/**打开或关闭闪关灯
	 * @param open
	 */
	private void switchLight(boolean open) {
		if (open == isOpen) {
			return;
		}
		isOpen = CameraManager.get().switchLight(open);
	}


	//类相关监听<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<


	//类相关监听>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

	//系统自带监听方法>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>


	//listener事件监听区(只要存在事件监听代码就是)>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>








	//内部类,尽量少用<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<



	//内部类,尽量少用>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

}

CameraScanActivity布局文件camera_scan_activity.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    style="@style/activity_page" >

    <SurfaceView
        android:id="@+id/svCameraScan"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center" />

    <!-- 必须在最底层,且不能指定宽高,否则扫描读取很难实现 -->
    <com.zxing.view.ViewfinderView
        android:id="@+id/vfvCameraScan"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <LinearLayout
        style="@style/ll_vertical_match_match"
        android:baselineAligned="false" >

        <RelativeLayout
            style="@style/topbar_bg"
            android:background="@color/white_alpha" >

            <TextView
                android:id="@+id/tvCameraScanReturn"
                style="@style/topbar_left_btn"
                android:text="          " />

            <TextView
                style="@style/topbar_title"
                android:layout_centerHorizontal="true"
                android:text="扫一扫" />
        </RelativeLayout>

        <LinearLayout
            style="@style/ll_vertical_match_match"
            android:layout_gravity="center_horizontal"
            android:layout_weight="1" >

            <TextView
                style="@style/text_middle_white"
                android:layout_margin="30dp"
                android:text="@string/camera_scan_remind" />
        </LinearLayout>

        <LinearLayout
            style="@style/ll_horizontal_match_wrap"
            android:layout_gravity="bottom"
            android:background="@color/white_alpha"
            android:gravity="center" >

            <LinearLayout
                style="@style/ll_vertical_wrap_wrap"
                android:layout_margin="12dp"
                android:paddingBottom="4dp"
                android:paddingLeft="12dp"
                android:paddingRight="12dp"
                android:paddingTop="4dp" >

                <ImageView
                    android:id="@+id/ivCameraScanReturn"
                    style="@style/wrap_wrap"
                    android:background="@drawable/cilcle_gray_to_white"
                    android:padding="12dp"
                    android:src="@drawable/back_black_light" />

                <TextView
                    style="@style/text_small"
                    android:layout_marginTop="4dp"
                    android:text="返回" />
            </LinearLayout>

            <LinearLayout
                style="@style/ll_vertical_wrap_wrap"
                android:layout_margin="12dp"
                android:paddingBottom="4dp"
                android:paddingLeft="12dp"
                android:paddingRight="12dp"
                android:paddingTop="4dp" >

                <ImageView
                    android:id="@+id/ivCameraScanLight"
                    style="@style/wrap_wrap"
                    android:background="@drawable/cilcle_gray_to_white"
                    android:padding="12dp"
                    android:src="@drawable/flash_light" />

                <TextView
                    style="@style/text_small"
                    android:layout_marginTop="4dp"
                    android:text="开灯/关灯" />
            </LinearLayout>

            <LinearLayout
                style="@style/ll_vertical_wrap_wrap"
                android:layout_margin="12dp"
                android:paddingBottom="4dp"
                android:paddingLeft="12dp"
                android:paddingRight="12dp"
                android:paddingTop="4dp" >

                <ImageView
                    android:id="@+id/ivCameraScanMyQRCode"
                    style="@style/wrap_wrap"
                    android:background="@drawable/cilcle_gray_to_white"
                    android:padding="12dp"
                    android:src="@drawable/qrcode" />

                <TextView
                    style="@style/text_small"
                    android:layout_marginTop="4dp"
                    android:text="我的名片" />
            </LinearLayout>
        </LinearLayout>
    </LinearLayout>

</FrameLayout>


布局文件因为使用了ZBLibrary中的一些style,color等,只有这个layout的话会出现一些错误。自己新建一个layout文件并把ViewfinderView放到最外层布局文件内就行了。当然下载好下面附上的源码就没这问题了。

对了,记得在AndroidManifest.xml中加上这些权限:

    <uses-permission android:name="android.permission.CAMERA" />

    <uses-feature android:name="android.hardware.camera" />

    <uses-feature android:name="android.hardware.camera.autofocus" />

    <uses-permission android:name="android.permission.FLASHLIGHT" />

 

附源码(欢迎Star,欢迎Fork)

 

GitHub源码      https://github.com/TommyLemon/Android-ZBLibrary 

开源中国源码    http://git.oschina.net/Lemon19950301/Android-ZBLibrary 

 

© 著作权归作者所有

孤独的探索号

孤独的探索号

粉丝 154
博文 23
码字总数 29911
作品 5
深圳
私信 提问
加载中

评论(2)

z
zlyjoe
支持
不懂技术的程序员
不懂技术的程序员
good
ZBLibrary 19.0 发布,Star 数已达 3K

更新内容: 新增一键自动删除所有编译缓存 build 目录的 Window 批处理脚本 clearAllBuildCache.bat; getActivity 抽象到 BaseActivity; 解决条形码与预览框的水平倾角超过30%识别不了,感...

孤独的探索号
2018/11/28
2.5K
0
Android进阶 - 二维码扫描

摘要 最近,在公司项目上需要加入“二维码扫描”的功能(Android端),笔者在网上查阅了一些资料,实现了这个功能。最后给自己做个笔记,给各位做下分享。 原理说明 “二维码扫描”实际上就是...

qiubs
2019/07/06
0
0
Android扫一扫:zxing的集成与优化

最近项目里需要实现二维码的扫描功能,扫描两个二维码然后得到数据进行绑定。目前比较常见的二维码扫描库就是zxing和zbar了,zxing是google官方的开源项目,有专门的维护,java编写。zbar使用...

猴亮屏
2019/02/12
133
0
Android快速开发框架 - Android-ZBLibrary

ZBLibrary-Android快速开发框架 MVP架构的Android快速开发框架, 提供一套开发标准(View,Data,Event)以及模板和工具类并规范代码。 封装层级少,简单高效兼容性好。 OKHttp、UIL图片加载、...

孤独的探索号
2016/04/21
6.9K
5
二维码扫描(横屏、竖屏、解决竖屏后拉伸问题、美化扫描框)

二维码扫描(横屏、竖屏、解决竖屏后拉伸问题、美化扫描框) 2013-09-29 16:39:37 我来说两句 作者:梦想天涯 收藏 我要投稿 是根据zxing的源码进行简化的,不过只支持横屏。 其实支持竖屏也...

Jonson
2014/03/03
1.3K
0

没有更多内容

加载失败,请刷新页面

加载更多

007. J.U.C 之锁的使用

1. Lock API 1. Locks 包类层次结构 2. Lock 接口 方法签名 描述 void lock(); 获取锁(不死不休) boolean tryLock(); 获取锁(浅尝辄止) boolean tryLock(long time, TimeUnit unit) throws ......

紫穹
38分钟前
27
0
如何确定Python变量的类型? - How to determine a Python variable's type?

问题: How do I see the type of a variable whether it is unsigned 32 bit, signed 16 bit, etc.? 如何查看变量的类型,无论是无符号32位,带符号16位等等? How do I view it? 我该如何看...

javail
今天
150
0
略谈分布式系统中的容器设计模式

本文作者:zytan_cocoa 略谈分布式系统中的容器设计模式 谭中意 2020/3/5 前言:云原生(Cloud Native)不仅仅是趋势,更是现在进行时,它是构建现代的,可弹性伸缩的,快速迭代的计算网络服...

百度开发者中心
03/11
135
0
a small thing that made me a little bit depressed

It was just two hours ago,specificly speaking It was 11:48 almost coming close to midneight. I was pratising singing songs in my renting room which is a sharing apartment . I re......

lost_myself
今天
111
0
OSChina 周日乱弹 —— 这中间几个月的地震、核爆、外星人、高达... 去哪了

Osc乱弹歌单(2020)请戳(这里) 【今日歌曲】 @薛定谔的兄弟 :分享洛神有语创建的歌单「我喜欢的音乐」: 《Elizabeth》- Ashram 手机党少年们想听歌,请使劲儿戳(这里) @巴拉迪维 :#共...

小小编辑
今天
259
1

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部