使用相机预览框架和旋转矩阵解决该问题。
在 Android 中,可以使用相机预览框架解决摄像头预览画面在横竖屏切换时视图位置改变的问题。该框架提供了 CameraPreview 类,通过该类实现 SurfaceHolder.Callback 实现接口,具体实现代码如下:
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private SurfaceHolder mHolder;
private Camera mCamera;
public CameraPreview(Context context, Camera camera) {
super(context);
mCamera = camera;
mHolder = getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
public void surfaceCreated(SurfaceHolder holder) {
try {
mCamera.setPreviewDisplay(holder);
mCamera.startPreview();
} catch (IOException e) {
Log.d(TAG, "Error setting camera preview: " + e.getMessage());
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
mCamera.stopPreview();
mCamera.release();
}
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
if (mHolder.getSurface() == null) {
return;
}
try {
mCamera.stopPreview();
} catch (Exception e) {
}
try {
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
} catch (Exception e) {
Log.d(TAG, "Error starting camera preview: " + e.getMessage());
}
}
}
在相机旋转时,需要计算旋转矩阵用于对预览画面进行旋转。可以通过重写 CameraPreview 类的 onMeasure() 方法实现该功能,具体代码如下:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
setMeasuredDimension(width, height);
if (mHolder != null) {
mHolder.setFixedSize(height, width);
final Camera.Parameters parameters = mCamera.getParameters();
final Camera.Size size = getBestPreviewSize(width, height, parameters);
if (size != null) {
parameters.setPreviewSize(size.width, size.height);
mCamera.setParameters(parameters);
final int orientation = getResources().getConfiguration().orientation;
if (orientation == Configuration.ORIENTATION_PORTRAIT) {
mCamera.setDisplayOrientation(90);
} else if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
mCamera.setDisplayOrientation(0);
}
final float ratio = (float) size.width / size.height;
final float viewRatio = (float) getWidth() / getHeight();
if (viewRatio > ratio) {
final int viewHeight = (int) (getWidth() / ratio);
setMeasuredDimension(getWidth(), viewHeight);
} else {
final int viewWidth = (int) (getHeight() * ratio);
setMeasuredDimension(viewWidth, getHeight());
}
}
}
}
private Camera.Size getBestPreviewSize(final int width, final int height, final Camera.Parameters parameters) {
Camera.Size result = null;
for (final Camera.Size size : parameters.getSupportedPreviewSizes()) {
if (size.width <= width && size.height <=