随着二维码使用的流行,现在基本上什么APP都会用到二维码功能,所以不管怎样,在项目中集成二维码功能都是非常有必要的。
ZXing
ZXing是由谷歌开发的一款条码,二维码扫描工具
官方github地址: https://github.com/zxing/zxing
这个工程非常庞大包含很多项目,这里主要说一下关于android方面的。
说明
首先需要说明,因为工作的关系,APP的开发一般使用Eclipse,当然偶尔也会用AS。所以这里的开发环境是基于Eclipse的。由于官方android部分,包含了剪切板,扫描历史,分享,扫描二维码等等功能。如果只使用扫码功能,就需要剔除其他的功能。
这里奉上一个自用的库,里面已经包含了最新的zxing.jar包,并且进行了一些界面修改,因为我电脑的操作系统系繁体中文的,所以要在简体操作系统上使用记得要将编码格式改为GBK
链接在此,点击我下载
效果图:
简单的使用
clone项目,并导入Eclipse后
选中项目,快捷键Alt+Enter,打开项目属性窗口,将项目设置为库
再新建一个安卓项目,重复操作打开项目属性窗口,点击Add按钮将库项目添加到新项目中去。
在新项目中添加按键监听事件1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21Button scanBarCodeButton = (Button) this.findViewById(R.id.btn_scan_barcode);
scanBarCodeButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
//打开扫描界面扫描条形码或二维码
Intent openCameraIntent = new Intent(BarCodeTestActivity.this,CaptureActivity.class);
startActivityForResult(openCameraIntent, 0);
}
});
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
//处理扫描结果(在界面上显示)
if (resultCode == RESULT_OK) {
Bundle bundle = data.getExtras();
String scanResult = bundle.getString("result");
resultTextView.setText(scanResult);
}
}
到这里就可以使用二维码扫描功能了,不要忘记在AndroidManifest.xml添加权限和对应Activity。
常用功能优化
横屏竖屏修改
1.修改CameraConfigurationManager类中的setDesiredCameraParameters方法1
2
3
4
5
6
7
8
9
10
11void setDesiredCameraParameters(Camera camera) {
Camera.Parameters parameters = camera.getParameters();
Log.d(TAG, "Setting preview size: " + cameraResolution);
parameters.setPreviewSize(cameraResolution.x, cameraResolution.y);
setFlash(parameters);
setZoom(parameters);
//**90度豎屏 0為橫屏
camera.setDisplayOrientation(90);
camera.setParameters(parameters);
}
2.修改CameraManager类中的getFramingRectInPreview方法1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20public Rect getFramingRectInPreview() {
if (framingRectInPreview == null) {
Rect rect = new Rect(getFramingRect());
Point cameraResolution = configManager.getCameraResolution();
Point screenResolution = configManager.getScreenResolution();
//**橫屏
//rect.left = rect.left * cameraResolution.x / screenResolution.x;
//rect.right = rect.right * cameraResolution.x / screenResolution.x;
//rect.top = rect.top * cameraResolution.y / screenResolution.y;
//rect.bottom = rect.bottom * cameraResolution.y / screenResolution.y;
//**豎屏
rect.left = rect.left * cameraResolution.y / screenResolution.x;
rect.right = rect.right * cameraResolution.y / screenResolution.x;
rect.top = rect.top * cameraResolution.x / screenResolution.y;
rect.bottom = rect.bottom * cameraResolution.x / screenResolution.y;
framingRectInPreview = rect;
}
return framingRectInPreview;
}
3.修改DecodeHandler类中的decode方法1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22private void decode(byte[] data, int width, int height) {
long start = System.currentTimeMillis();
Result rawResult = null;
//*************************竖屏解码段*****************************
byte[] rotatedData = new byte[data.length];
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++)
rotatedData[x * height + height - y - 1] = data[x + y * width];
}
int tmp = width; // Here we are swapping, that's the difference to #11
width = height;
height = tmp;
PlanarYUVLuminanceSource source = CameraManager.get().buildLuminanceSource(rotatedData, width, height);
//**************************************************************
//*****橫屏解碼段*****
//PlanarYUVLuminanceSource source = CameraManager.get().buildLuminanceSource(data, width, height);
......
}
竖屏拉伸问题
改为竖屏显示时,常常伴有画面拉伸的现象,解决该问题可以修改CameraConfigurationManager类中的initFromCameraParameters方法1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23void initFromCameraParameters(Camera camera) {
Camera.Parameters parameters = camera.getParameters();
previewFormat = parameters.getPreviewFormat();
previewFormatString = parameters.get("preview-format");
Log.d(TAG, "Default preview format: " + previewFormat + '/' + previewFormatString);
WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = manager.getDefaultDisplay();
screenResolution = new Point(display.getWidth(), display.getHeight());
Log.d(TAG, "Screen resolution: " + screenResolution);
//---------------------竖屏拉伸解决函数-----------------
Point screenResolutionForCamera = new Point();
screenResolutionForCamera.x = screenResolution.x;
screenResolutionForCamera.y = screenResolution.y;
// preview size is always something like 480*320, other 320*480
if (screenResolution.x < screenResolution.y) {
screenResolutionForCamera.x = screenResolution.y;
screenResolutionForCamera.y = screenResolution.x;
}
cameraResolution = getCameraResolution(parameters, screenResolutionForCamera);
//-----------------------------------------------------
Log.d(TAG, "Camera resolution: " + screenResolution);
}
扫描框美化
绘制白色边框及绿色边角
1.扫描框是自定义组件,要改变样式需要修改ViewfinderView类的onDraw方法,首先添加白色边框方法和边角方法1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24private void drawFrame(Canvas canvas, Rect frame){
//**繪製白色邊框
paint.setColor(Color.WHITE);
canvas.drawRect(frame.left, frame.top, frame.right + 1, frame.top + 2, paint);
canvas.drawRect(frame.left, frame.top + 2, frame.left + 2, frame.bottom - 1, paint);
canvas.drawRect(frame.right - 1, frame.top, frame.right + 1, frame.bottom - 1, paint);
canvas.drawRect(frame.left, frame.bottom - 1, frame.right + 1, frame.bottom + 1, paint);
}
private void drawFrameCorner(Canvas canvas, Rect frame){
//**繪製4個綠色邊角
paint.setColor(Color.GREEN);
// 左上角
canvas.drawRect(frame.left, frame.top, frame.left + 20,frame.top + 10, paint);
canvas.drawRect(frame.left, frame.top, frame.left + 10,frame.top + 20, paint);
// 右上角
canvas.drawRect(frame.right - 20, frame.top, frame.right,frame.top + 10, paint);
canvas.drawRect(frame.right - 10, frame.top, frame.right,frame.top + 20, paint);
// 左下角
canvas.drawRect(frame.left, frame.bottom - 10, frame.left + 20,frame.bottom, paint);
canvas.drawRect(frame.left, frame.bottom - 20, frame.left + 10,frame.bottom, paint);
// 右下角
canvas.drawRect(frame.right - 20, frame.bottom - 10, frame.right,frame.bottom, paint);
canvas.drawRect(frame.right - 10, frame.bottom - 20, frame.right,frame.bottom, paint);
}
扫描线循环滚动
2.扫描线循环滚动关键代码段1
2
3
4
5
6
7int move = frame.top + slideTop; //**掃描線循環滾動
if ((slideTop += SPEEN_DISTANCE) < frame.bottom - frame.top) {
canvas.drawRect(frame.left + 2, move-1, frame.right - 1, move+2, paint);
invalidate();
}else{
slideTop = 0;
}
3.修改ViewfinderView类的onDraw方法改变扫描框样式,只贴出关键部分1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public void onDraw(Canvas canvas) {
......
if (resultBitmap != null) {
// Draw the opaque result bitmap over the scanning rectangle
//paint.setAlpha(OPAQUE);
paint.setAlpha(OPAQUE);
canvas.drawBitmap(resultBitmap, frame.left, frame.top, paint);
}else{
//******************************扫描框修改*****************************
// Draw a two pixel solid black border inside the framing rect
drawFrame(canvas, frame); //**繪製白色邊框
drawFrameCorner(canvas, frame); //**繪製4個綠色邊角
// 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;
int middle = frame.height() / 2 + frame.top;
int move = frame.top + slideTop; //**掃描線循環滾動
if ((slideTop += SPEEN_DISTANCE) < frame.bottom - frame.top) {
canvas.drawRect(frame.left + 2, move-1, frame.right - 1, move+2, paint);
invalidate();
}else{
slideTop = 0;
}
//***************************************************************
.....
}
}
实现重复扫描功能
有些应用可能会需要用到连续扫描的功能,例如当做扫描枪使用之类什么的。修改CaptureActivity的handleDecode方法1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29public 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();
}else {
Intent resultIntent = new Intent();
Bundle bundle = new Bundle();
bundle.putString("result", resultString);
resultIntent.putExtras(bundle);
this.setResult(RESULT_OK, resultIntent);
}
hder.postDelayed(rePreview, 2500); // **解碼回調函數
}
/*
* 掃描界面回調
*/
private static Handler hder = new Handler();
Runnable rePreview = new Runnable() {
public void run() {
if(LoginActivity.connectSwitch){ connect(); }
CameraManager.get().startPreview();
handler.restartPreviewAndDecode();
}
};
关于回调方法,第二个参数是回调时间,部分机型不能设置太短,会造成程序崩溃
我对小米,索尼,华为,夏普等手机进行测试,2500毫秒是临界点,个人猜测是手机摄像头硬件的限制1
hder.postDelayed(rePreview, 2500);