【发布时间】:2014-01-20 05:49:45
【问题描述】:
编辑
从倒置纵向旋转到横向之一并从那里旋转到倒置纵向时也是一个问题。我已经在默认的相机应用程序上测试了这些情况,它似乎没有任何这些问题.
结束编辑
我有一个自定义相机,当它旋转 180 度时,从一个风景到另一个风景会显示一个倒置的预览。我在我的代码中使用了一个 OrientationEventListener 像这样。
mCamera.setDisplayOrientation 在setDisplayOrientation 中调用,我使用roundOrientation(orientation,orientationHistory) 将方向四舍五入为0,90,180,270,并使用getDisplayRotation 获得自然显示旋转。我在initializeFirstTime 中实例化侦听器并启用它initializeFirstTime 和如果从initializeSecondTime 的暂停状态恢复。我禁用onPause 中的侦听器。我在onResume 中调用initializeFirstTime 或initializeSecondTime。
:
class MyOrientationEventListener extends OrientationEventListener
{
@Override
public void onOrientationChanged(int orientation)
{
if(orientation==ORIENTATION_UNKNOWN)
return;
mOrientation=roundOrientation(orientation,0);
int orientationCompensation=getDisplayRotation(CameraActivity.this);
if(mOrientationCompensation!=orientationCompensation)
mOrientationCompensation=orientationCompensation;
}
public MyOrientationEventListener(Context context) {
super(context);
}
private int roundOrientation(int orientation, int orientationHistory) {
boolean changeOrientation = false;
final int ORIENTATION_HYSTERESIS=5;//a tolerance value above the limit
if (orientationHistory == OrientationEventListener.ORIENTATION_UNKNOWN) {
changeOrientation = true;
} else {
int dist = Math.abs(orientation - orientationHistory);
dist = Math.min(dist, 360 - dist);
changeOrientation = (dist >= 45 +ORIENTATION_HYSTERESIS );
}
if (changeOrientation) {
return ((orientation + 45) / 90 * 90) % 360;
}
return orientationHistory;
}
}
private void setDisplayOrientation()
{
mDisplayRotation=getDisplayRotation(this);
mDisplayOrientation=getDisplayOrientation(mDisplayRotation, CameraInfo.CAMERA_FACING_BACK);
mCamera.setDisplayOrientation(mDisplayOrientation);
}
private int getDisplayOrientation(int degrees, int cameraId) {
// See android.hardware.Camera.setDisplayOrientation for
// documentation.
Camera.CameraInfo info = new Camera.CameraInfo();
Camera.getCameraInfo(cameraId, info);
int result;
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
result = (info.orientation + degrees) % 360;
result = (360 - result) % 360; // compensate the mirror
} else { // back-facing
result = (info.orientation - degrees + 360) % 360;
}
return result;
}
private int getDisplayRotation(Activity activity) {
int rotation = activity.getWindowManager().getDefaultDisplay()
.getRotation();
switch (rotation) {
case Surface.ROTATION_0: return 0;
case Surface.ROTATION_90: return 90;
case Surface.ROTATION_180: return 180;
case Surface.ROTATION_270: return 270;
}
return 0;
}
private MyOrientationEventListener mOrientationListener;
private int mOrientation=OrientationEventListener.ORIENTATION_UNKNOWN;
private int mOrientationCompensation=0;
private int mDisplayRotation;
private int mDisplayOrientation;
这两个方法用于激活OrientationEventListener:
private void initializeFirstTime()
{
//checking if previously initialized and setting camera parameters
mOrientationListener=new MyOrientationEventListener(CameraActivity.this);
mOrientationListener.enable();
mFirstTimeInitialized=true;
}
private void initializeSecondTime()
{
mOrientationListener.enable();
}
Camera Preview 像这样开始、停止和重新启动:
private void startPreview() throws CameraHardwareException
{
//check if called before onPause or after onResume,
//open the Camera if null,stop the preview,set the parameters
setDisplayOrientation();
try
{
Log.d(TAG, "Trying to start the preview");
mCamera.startPreview();
}
catch(Throwable ex)
{
closeCamera();
throw new RuntimeException("Could not start camera preview");
}
mPreviewing=true;
}
Activity 生命周期方法是这样实现的:
@Override
public void onResume()
{
super.onResume();
mPausing=false;
//check condition for SurfaceHolder
//probsbly happens if camera has paused and is resuming
if(mStatus==PREVIEW_STOPPED)
{
try {
startPreview();
} catch (CameraHardwareException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(surfaceHolder!=null)
{
if(!mFirstTimeInitialized)
initializeFirstTime();
else
initializeSecondTime();
}
keepScreenOnAwhile();
if(mStatus==CAMERA_IDLE)
{
mResumeTime=SystemClock.uptimeMillis();
handler.sendEmptyMessageDelayed(CHECK_DISPLAY_ROTATION, 100);
}
}
@Override
public void onPause()
{
mPausing=true;
stopPreview();
closeCamera();
resetScreenOn();
if(mFirstTimeInitialized)
mOrientationListener.disable();
handler.removeMessages(FIRST_TIME_INIT);
handler.removeMessages(CLEAR_SCREEN_DELAY);
super.onPause();
}
SurfaceHolder.Callbacks 方法已在此处实现:
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
if(holder.getSurface()==null)
{
Log.d(TAG, "holder.getSurface()=null");
return;
}
//stash the holder here for later use,useful if onResume needs to be invoked after this.
surfaceHolder=holder;
if(mCamera==null)
return;
//sometimes surfaceChanged is called after onPause or before onResume,ignore it
if(mPausing || isFinishing())
return;
if(mStatus==PREVIEW_STOPPED)
try {
startPreview();
} catch (CameraHardwareException e1) {
Log.e(TAG, "Error starting the preview");
}
if(!mPreviewing)
try {
startPreview();
} catch (CameraHardwareException e) {
Log.e(TAG,"Could not get the camera");
}
if(!mFirstTimeInitialized)
if(getDisplayRotation(this)!=mDisplayOrientation)
setDisplayOrientation();
if(mPreviewing && holder.isCreating())
{
setPreviewDisplay(holder);
}
if(!mFirstTimeInitialized)
handler.sendEmptyMessage(FIRST_TIME_INIT);
else
initializeSecondTime();
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
//nothing here
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
stopPreview();
surfaceHolder=null;
}
方向事件侦听器在 onResume 和 surfaceChanged 中启用,无论我猜哪个调用最快,然后在 onPause 中禁用。OrientationEventListener 仅在 initializeFirstTime 中实例化。
编辑:
发生这种情况是因为我没有正确启用OrientationEventListener。我还为影响图像旋转的参数设置了旋转:
mParameters.setRotation(rotation);
【问题讨论】:
-
default Camera application and it does not seem to have any of these problems 因为默认的相机应用将屏幕方向锁定为横向(相机的自然方向)。如果我理解正确,您的活动设置为
android:screenOrientation=fullSensor -
是的,我正在使用
android:screenOrientation=fullSensor.Have tried to change with SurfaceHolder.Callbacks -
@AlexCohn 我没有在
layout-land中为CameraActvity添加任何布局文件,这会有什么不同。 -
不,你不需要
layout-land,除非你想要一个不同的横向布局。
标签: android android-camera landscape android-orientation