我在這裏發現了很多關於安卓相機預覽方向問題的問題。所有修復都涉及將屏幕方向固定爲橫向或調用camera.setDisplayOrientation(90)或調用params.setRotation(90)。我無法找到橫向放置時實際使其工作的設置組合。如果手機處於橫向模式,Android相機預覽方向不正確
使用android:screenOrientation =「landscape」將活動固定爲橫向模式。
我的問題是,如果我以縱向方向握住相機並啓動應用程序,它可以正常工作(我的意思是它正確地將圖像顯示爲風景)。如果我在啓動應用程序時以橫向方向握住相機,則圖像會全部混亂(交錯)。如果我使用camera.setDisplayOrientation(90);圖片不再混亂,但圖像側向。奇怪的是,如果我刪除android:screenOrientation =「風景」並允許屏幕旋轉,我仍然有同樣的問題,但如果我將手機旋轉到縱向,它在縱向上看起來不錯。如果我將其旋轉回風景,那麼它在風景中看起來不錯!我唯一的問題是它首次啓動時無法正常工作。
import java.util.List;
import android.content.Context;
import android.graphics.Color;
import android.hardware.Camera;
import android.hardware.Camera.Parameters;
import android.hardware.Camera.Size;
import android.util.AttributeSet;
import android.util.Log;
import android.view.*;
public class CameraView extends SurfaceView
{
//Callback for the surfaceholder
SurfaceHolder.Callback surfaceHolderListener = new SurfaceHolder.Callback() {
public void surfaceCreated(SurfaceHolder holder) {
try {
camera=Camera.open();
} catch(Exception e) {
Log.e("CameraView","Couldn't open the camera.",e);
}
try {
camera.setPreviewDisplay(previewHolder);
} catch (Throwable e) {
Log.e("CameraView","Couldn't call setPreviewDisplay.",e);
}
}
public void surfaceChanged(SurfaceHolder surfaceHolder, int format, int w, int h) {
if(camera!=null) {
Parameters params = camera.getParameters();
List<Size> sizes = params.getSupportedPreviewSizes();
Size optimalSize = getOptimalPreviewSize(sizes, w, h);
params.setPreviewSize(optimalSize.width, optimalSize.height);
camera.setParameters(params);
camera.startPreview();
}
}
public void surfaceDestroyed(SurfaceHolder arg0) {
if(camera!=null) {
camera.setPreviewCallback(null);
camera.stopPreview();
camera.release();
}
}
private Size getOptimalPreviewSize(List<Size> sizes, int w, int h) {
final double ASPECT_TOLERANCE = 0.05;
double targetRatio = (double) w/h;
if (sizes == null) return null;
Size optimalSize = null;
double minDiff = Double.MAX_VALUE;
int targetHeight = h;
// Try to find an size match aspect ratio and size
for (Size size : sizes) {
double ratio = (double) size.width/size.height;
if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue;
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
// Cannot find the one match the aspect ratio, ignore the requirement
if (optimalSize == null) {
minDiff = Double.MAX_VALUE;
for (Size size : sizes) {
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
}
return optimalSize;
}
};
public CameraView(Context ctx) {
super(ctx);
previewHolder = this.getHolder();
previewHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
previewHolder.addCallback(surfaceHolderListener);
setBackgroundColor(Color.TRANSPARENT);
}
public CameraView(Context ctx, AttributeSet attrs) {
super(ctx, attrs);
}
private Camera camera;
private SurfaceHolder previewHolder;
}
編輯: 真正的問題似乎是,後surfaceChanged其螺絲東西有事。我發現如果我啓動相機預覽,然後在surfaceChanged的最後添加一個調試點,則相機看起來很好。然後,如果我向前走了大約20步,它突然看起來搞砸了。
我解決了這個問題(通過一種我認爲是完全破解的方式),方法是使用方向更改偵聽器一次更新方向,然後禁用它自己。我只需要在視圖最初設置後激活的東西。我可能可以在其他地方做到這一點。
如果有人有任何想法如何解決這個問題,而不是這是完全愚蠢的,請幫助!
/** This works fine for me, but it's a hack. */
import java.util.List;
import android.content.Context;
import android.graphics.Color;
import android.hardware.Camera;
import android.hardware.Camera.Parameters;
import android.hardware.Camera.Size;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.OrientationEventListener;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class CameraView3
extends SurfaceView
{
private static Size getOptimalPreviewSize(List<Size> sizes, int w, int h) {
final double ASPECT_TOLERANCE = 0.05;
double targetRatio = (double) w/h;
if (sizes == null) return null;
Size optimalSize = null;
double minDiff = Double.MAX_VALUE;
int targetHeight = h;
// Try to find an size match aspect ratio and size
for (Size size : sizes) {
double ratio = (double) size.width/size.height;
if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue;
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
// Cannot find the one match the aspect ratio, ignore the requirement
if (optimalSize == null) {
minDiff = Double.MAX_VALUE;
for (Size size : sizes) {
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
}
return optimalSize;
}
private class CameraSurfaceHolder
extends OrientationEventListener
implements SurfaceHolder.Callback
{
CameraSurfaceHolder(Context ctx) {
super(ctx);
}
public void surfaceCreated(SurfaceHolder holder) {
try {
camera= Camera.open();
} catch(Exception e) {
Log.e("CameraView","Couldn't open the camera.",e);
}
try {
camera.setPreviewDisplay(previewHolder);
} catch (Throwable e) {
Log.e("CameraView","Couldn't call setPreviewDisplay.",e);
}
}
public void surfaceChanged(SurfaceHolder surfaceHolder, int format, int w, int h) {
}
public void surfaceDestroyed(SurfaceHolder arg0) {
if(camera!=null) {
camera.setPreviewCallback(null);
camera.stopPreview();
camera.release();
}
}
@Override
public void onOrientationChanged(int orientation) {
if(camera!=null) {
DisplayMetrics dm = ctx.getResources().getDisplayMetrics();
camera.stopPreview();
CameraView3.this.layout(0, 0, dm.widthPixels-1, dm.heightPixels-1);
camera.startPreview();
disable();
return;
}
}
}
public CameraView3(Context ctx) {
super(ctx);
this.ctx = ctx;
previewHolder = this.getHolder();
previewHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
surfaceHolderListener = new CameraSurfaceHolder(ctx);
previewHolder.addCallback(surfaceHolderListener);
surfaceHolderListener.enable();
setBackgroundColor(Color.TRANSPARENT);
}
private Context ctx;
private Camera camera;
private SurfaceHolder previewHolder;
private CameraSurfaceHolder surfaceHolderListener;
private Size optimalSize;
}
總之,我發佈的第一個版本在我的Nexus One上工作得很好。但是,它在我的Skyrocket上不起作用。我需要使用第二個版本才能在那裏工作。
爲什麼在您的工作代碼中,您是否使用寬度和高度減1?如果沒有-1,我的代碼不能在Skyrocket上運行,但是它的代碼是-1。正如你所說,這感覺就像一個徹頭徹尾的黑客,但它是我發現這個奇怪行爲的唯一解決方案:(我不想減1,因爲它不完全填充屏幕......只是嘗試 –