Ответ 1
У меня была такая же проблема, как год назад. Кроме того, мне приходилось иметь дело с фронтальной и задней камерой. Я не очень много помню о коде, но я попробовал его, прежде чем публиковать этот ответ, и он все еще работает как шарм.
Надеюсь, вы сможете копать и сравнивать с вашим кодом. Я могу поделиться больше кода, если вы только что-то работаете;)
/**
* A simple wrapper around a Camera and a SurfaceView that renders a centered preview of the Camera
* to the surface. We need to center the SurfaceView because not all devices have cameras that
* support preview sizes at the same aspect ratio as the device display.
*/
public class Preview extends ViewGroup implements SurfaceHolder.Callback {
SurfaceView mSurfaceView;
SurfaceHolder mHolder;
Camera.Size mPreviewSize;
List<Camera.Size> mSupportedPreviewSizes;
Camera mCamera;
private Context context;
private int mCameraId;
public boolean use_front_camera;
public Preview(Context context, int cameraId) {
super(context);
this.context = context;
mCameraId = cameraId;
use_front_camera = true;
mSurfaceView = new SurfaceView(context);
addView(mSurfaceView);
// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
mHolder = mSurfaceView.getHolder();
mHolder.addCallback(this);
}
public void setCamera(Camera camera) {
mCamera = camera;
if (mCamera != null) {
mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
requestLayout();
}
}
public void switchCamera(Camera camera) {
setCamera(camera);
try {
camera.setPreviewDisplay(mHolder);
} catch (IOException exception) {
android.util.Log.e(IdelityConstants.DEBUG_IDELITY_KEY_LOG, "IOException caused by setPreviewDisplay()", exception);
}
Camera.Parameters parameters = camera.getParameters();
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
requestLayout();
camera.setParameters(parameters);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// We purposely disregard child measurements because act as a
// wrapper to a SurfaceView that centers the camera preview instead
// of stretching it.
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
//MUST CALL THIS
setMeasuredDimension(width, height);
if (mSupportedPreviewSizes != null) {
mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height);
}
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
if (changed && getChildCount() > 0) {
final View child = getChildAt(0);
final int width = r - l;
final int height = b - t;
int previewWidth = width;
int previewHeight = height;
if (mPreviewSize != null) {
/**
* Como el calculo se hace con la cámara en modo landscape y luego toca
* girar la cámara para que se vea bien, se pasan los valores cambiados.
*/
previewWidth = mPreviewSize.height;
previewHeight = mPreviewSize.width;
}
// Center the child SurfaceView within the parent.
if (width * previewHeight < height * previewWidth) {
final int scaledChildWidth = previewWidth * height / previewHeight;
child.layout((width - scaledChildWidth) / 2, 0,
(width + scaledChildWidth) / 2, height);
} else {
final int scaledChildHeight = previewHeight * width / previewWidth;
child.layout(0, (height - scaledChildHeight) / 2,
width, (height + scaledChildHeight) / 2);
}
}
}
public void surfaceCreated(SurfaceHolder holder) {
// The Surface has been created, acquire the camera and tell it where
// to draw.
try {
if (mCamera != null) {
mCamera.setPreviewDisplay(holder);
}
} catch (IOException exception) {
android.util.Log.e(IdelityConstants.DEBUG_IDELITY_KEY_LOG, "IOException caused by setPreviewDisplay()", exception);
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
// Surface will be destroyed when we return, so stop the preview.
// if (mCamera != null) {
// mCamera.stopPreview();
// }
}
private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) {
final double ASPECT_TOLERANCE = 0.1;
double targetRatio = (double) w / h;
if (sizes == null) return null;
Camera.Size optimalSize = null;
double minDiff = Double.MAX_VALUE;
int targetHeight = h;
// Try to find an size match aspect ratio and size
for (Camera.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 (Camera.Size size : sizes) {
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
}
return optimalSize;
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
// Now that the size is known, set up the camera parameters and begin
// the preview.
if (mCamera == null)
return;
Camera.Parameters parameters = mCamera.getParameters();
parameters.setFlashMode(Camera.Parameters.FLASH_MODE_AUTO);
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
parameters.setJpegQuality(100);
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
List<Camera.Size> sizes = parameters.getSupportedPictureSizes();
Camera.Size size = sizes.get(0);
for(int i=0;i<sizes.size();i++)
{
if(sizes.get(i).width > size.width)
size = sizes.get(i);
}
parameters.setPictureSize(size.width, size.height);
requestLayout();
mCamera.setParameters(parameters);
mCamera.setDisplayOrientation(getCameraDisplayOrientation((FragmentActivity)context, mCameraId));
mCamera.startPreview();
}
public static int getCameraDisplayOrientation(FragmentActivity activity, int cameraId) {
Camera.CameraInfo info = new Camera.CameraInfo();
Camera.getCameraInfo(cameraId, info);
int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
int degrees = 0;
switch (rotation) {
case Surface.ROTATION_0: degrees = 0; break;
case Surface.ROTATION_90: degrees = 90; break;
case Surface.ROTATION_180: degrees = 180; break;
case Surface.ROTATION_270: degrees = 270; break;
}
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;
}
/** A safe way to get an instance of the Camera object. */
public static Camera getCameraInstance(int cameraIndex){
Camera c = null;
try {
c = Camera.open(cameraIndex); // attempt to get a Camera instance
}
catch (Exception e){
// Camera is not available (in use or does not exist)
android.util.Log.e(IdelityConstants.ERROR_IDELITY_KEY_LOG, "Camera is not available: " + e.getMessage());
}
return c; // returns null if camera is unavailable
}
}
вот XML, его простой (вы увидите на скриншоте). Единственное важное значение имеет FrameLayout с id: capture_evidence_camera_preview
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="0dp"
android:id="@+id/capture_evidence_linearLayout_camera"
android:layout_weight="3"
android:layout_gravity="center_horizontal">
<FrameLayout
android:id="@+id/capture_evidence_camera_preview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true"/>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/capture_evidence_default_text_number_evidence"
android:id="@+id/capture_evidence_textView_value_typed"
android:textSize="50sp"
android:textColor="@color/idelity_blanco"
android:gravity="center_horizontal"
android:paddingLeft="5dp"
android:paddingRight="5dp"
android:background="#d2000000"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:paddingTop="8dp"
android:paddingBottom="8dp" />
</RelativeLayout>
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1">
<net.idelity.idelitymobile.ui.helpers.IdelityButton
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:text="@string/button_back"
android:id="@+id/capture_evidence_button_cancel"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:background="@drawable/button_gray"
android:textColor="@color/idelity_blanco"
android:textSize="20sp"
android:paddingLeft="40dp"
android:paddingRight="40dp"
android:textStyle="bold" />
<net.idelity.idelitymobile.ui.helpers.IdelityButton
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="@+id/capture_evidence_button_capture_evidence"
android:layout_alignParentBottom="true"
android:layout_toRightOf="@+id/capture_evidence_button_cancel"
android:layout_toEndOf="@+id/capture_evidence_button_cancel"
android:background="@drawable/take_photo_button_camera"
android:textSize="25sp"
android:textColor="@color/idelity_blanco"
android:textStyle="bold"
android:text="@string/capture_evidence_button_capture_evidence"
android:paddingBottom="10dp" />
</RelativeLayout>
Используется в FragmentActivity (я могу поделиться им, если вам это нужно)