0.前言:
上一篇我们简单的玩了玩Zxing,将官方的Demo跑了下,有一个问题就是,这哥们屏幕是横着的,我们做的APP大多数都是竖着的。这肯定不开心的。闲话不多说,咱直接开始进入正题。把昨天的代码down下来直接改。
1.xml切换成竖屏试错:
观察清单文件:
<application
android:allowBackup="true"
android:icon="@drawable/launcher_icon"
android:label="@string/app_name"
android:logo="@drawable/launcher_icon">
<activity
android:name=".CaptureActivity"
android:clearTaskOnLaunch="true"
.......
很明显,CaptureActivity.java是我们需要关注的类。
现在我在清单文件内手动将其设为竖屏。
<activity
...
android:screenOrientation="portrait"
.../>
但是这只是看着竖屏了,实际上还无法扫描。
所以只能能另寻办法。
2.解决竖屏带来的问题—不能扫码:
其中的原理我试图整理,但是本人水平有限,想透彻搞明白所有的细节,还是需要花点时间,涉及到底层Camera原理,甚至扫码的算法,所以这里我就不强行解释了,等后面真的搞明白之后再来阐释这个问题,但是在本文尾部的推荐的大神博客内有所论述这个问题。现阶段就先操作操作吧。
温馨提示:注意 add by tancolo 和 end 的区间才是需要添加的代码。
step_1.删除 android:screenOrientation=”sensorLandscape”
AndroidManifest.xml
step_2.CaptureActivity内部类MyOrientationDetector使用。
添加内部类
private class MyOrientationDetector extends OrientationEventListener {
private int lastOrientation = -1;
MyOrientationDetector(Context context) {
super(context);
}
void setLastOrientation(int rotation) {
switch (rotation) {
case Surface.ROTATION_90:
lastOrientation = 270;
break;
case Surface.ROTATION_270:
lastOrientation = 90;
break;
default:
lastOrientation = -1;
}
}
@Override
public void onOrientationChanged(int orientation) {
Log.d(TAG, "orientation:" + orientation);
if (orientation > 45 && orientation < 135) {
orientation = 90;
} else if (orientation > 225 && orientation < 315) {
orientation = 270;
} else {
orientation = -1;
}
if ((orientation == 90 && lastOrientation == 270) || (orientation == 270 && lastOrientation == 90)) {
Log.i(TAG, "orientation:" + orientation + "lastOrientation:" + lastOrientation);
Intent intent = getIntent();
finish();
startActivity(intent);
lastOrientation = orientation;
Log.i(TAG, "SUCCESS");
}
}
}
声明MyOrientationDetector变量
MyOrientationDetector myOrientationDetector;
onCreate中使用
//add by tancolo
myOrientationDetector = new MyOrientationDetector(this);
myOrientationDetector.setLastOrientation(getWindowManager().getDefaultDisplay().getRotation());
//end add
onResume中使用
if (prefs.getBoolean(PreferencesActivity.KEY_DISABLE_AUTO_ORIENTATION, true)) {
setRequestedOrientation(getCurrentOrientation());
} else {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR); // 旋转
myOrientationDetector.enable(); //启用监听
}
onPause中使用
//add by tancolo
myOrientationDetector.disable();
//end add
super.onPause();
step_3.获得准确的相机预览框 (CameraManager.java)。
getFramingRectInPreview()
/**
* Like {@link #getFramingRect} but coordinates are in terms of the preview frame,
* not UI / screen.
*
* @return {@link Rect} expressing barcode scan area in terms of the preview size
*/
public synchronized Rect getFramingRectInPreview() {
if (framingRectInPreview == null) {
Rect framingRect = getFramingRect();
if (framingRect == null) {
return null;
}
Rect rect = new Rect(framingRect);
Point cameraResolution = configManager.getCameraResolution();
Point screenResolution = configManager.getScreenResolution();
if (cameraResolution == null || screenResolution == null) {
// Called early, before init even finished
return null;
}
//add by tancolo
if(screenResolution.x < screenResolution.y){
// portrait
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;
} else {
// landscape
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;
}
// end add
// 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;
framingRectInPreview = rect;
}
return framingRectInPreview;
}
step_4.修改PreviewCallback.java
onPreviewFrame()
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
Point cameraResolution = configManager.getCameraResolution();
Handler thePreviewHandler = previewHandler;
if (cameraResolution != null && thePreviewHandler != null) {
//add by tancolo
Point screenResolution = configManager.getScreenResolution();
Message message;
if (screenResolution.x < screenResolution.y){
// portrait
message = thePreviewHandler.obtainMessage(previewMessage, cameraResolution.y,
cameraResolution.x, data);
} else {
// landscape
message = thePreviewHandler.obtainMessage(previewMessage, cameraResolution.x,
cameraResolution.y, data);
}
// Message message = thePreviewHandler.obtainMessage(previewMessage, cameraResolution.x,
// cameraResolution.y, data);
//end add
message.sendToTarget();
previewHandler = null;
} else {
Log.d(TAG, "Got preview callback, but no handler or resolution available");
}
}
step_5.DecodeHandler.java
decode()
private void decode(byte[] data, int width, int height) {
long start = System.currentTimeMillis();
//add by tancolo
if (width < height) {
// portrait
byte[] rotatedData = new byte[data.length];
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++)
rotatedData[y * width + width - x - 1] = data[y + x * height];
}
data = rotatedData;
}
//end add
Result rawResult = null;
PlanarYUVLuminanceSource source = activity.getCameraManager().buildLuminanceSource(data, width, height);
if (source != null) {
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
try {
rawResult = multiFormatReader.decodeWithState(bitmap);
} catch (ReaderException re) {
// continue
} finally {
multiFormatReader.reset();
}
}
Handler handler = activity.getHandler();
if (rawResult != null) {
// Don't log the barcode contents for security.
long end = System.currentTimeMillis();
Log.d(TAG, "Found barcode in " + (end - start) + " ms");
if (handler != null) {
Message message = Message.obtain(handler, R.id.decode_succeeded, rawResult);
Bundle bundle = new Bundle();
bundleThumbnail(source, bundle);
message.setData(bundle);
message.sendToTarget();
}
} else {
if (handler != null) {
Message message = Message.obtain(handler, R.id.decode_failed);
message.sendToTarget();
}
}
}
step_6.运行Over,验证效果。
Demo:
https://github.com/zj614android/ZxingPortrait
Thanks:
Google ZXing系列讲解(一)——导入AS
Google ZXing系列讲解(二)——生成WIFi二维码
Google ZXing系列讲解(三)——ZXing 目录结构与主体流程
Google ZXing系列讲解(四)——ZXing 解决竖屏扫描问题
Google ZXing系列讲解(五)——ZXing 仿微信扫描UI