2011-10-02 21 views
7

Soy muy nuevo en el desarrollo de Android, y estoy tratando de obtener una configuración de aplicación de cámara simple. Hasta ahora tengo una aplicación de cámara que tiene botones de "cambiar cámara" y "tomar foto" dentro del menú que funcionan bien.¿Cómo puedo configurar el tamaño de vista previa de la cámara a pantalla completa con Android API?

El único problema que tengo es que estoy tratando de encontrar la manera de hacer que la pantalla sea a pantalla completa. En este momento, la cámara solo aparece en el centro de la pantalla y solo ocupa aproximadamente 1/4 de la pantalla.

Código MainActivity

package assist.core; 

import android.app.Activity; 
import android.app.AlertDialog; 
import android.hardware.Camera; 
import android.hardware.Camera.PictureCallback; 
import android.hardware.Camera.ShutterCallback; 
import android.hardware.Camera.CameraInfo; 
import android.os.Bundle; 
import android.view.Window; 
import android.view.WindowManager; 
import android.view.Menu; 
import android.view.MenuInflater; 
import android.view.MenuItem; 
import android.util.Log; 

import java.io.FileNotFoundException; 
import java.io.FileOutputStream; 
import java.io.IOException; 

public class MainActivity extends Activity { 

    private final String TAG = "MainActivity"; 
    private Preview mPreview; 
    Camera mCamera; 
    int numberOfCameras; 
    int cameraCurrentlyLocked; 

    //The first rear facing camera 
    int defaultCameraId; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 

     //Hide the window title. 
     requestWindowFeature(Window.FEATURE_NO_TITLE); 
     getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); 

     //Create a RelativeLayout container that will hold a SurfaceView, 
     //and set it as the content of our activity. 
     mPreview = new Preview(this); 
     setContentView(mPreview); 

     //Find the total number of cameras available 
     numberOfCameras = Camera.getNumberOfCameras(); 

     //Find the ID of the default camera 
     CameraInfo cameraInfo = new CameraInfo(); 
     for (int i = 0; i < numberOfCameras; i++) { 
      Camera.getCameraInfo(i, cameraInfo); 
      if(cameraInfo.facing == CameraInfo.CAMERA_FACING_BACK) { 
       defaultCameraId = i; 
      } 
     } 
    } 

    @Override 
    protected void onResume() { 
     super.onResume(); 

     //Open the default i.e. the first rear facing camera. 
     mCamera = Camera.open(); 
     cameraCurrentlyLocked = defaultCameraId; 
     mPreview.setCamera(mCamera); 
    } 

    @Override 
    protected void onPause() { 
     super.onPause(); 

     //Because the Camera object is a shared resource, it's very 
     //Important to release it when the activity is paused. 
     if (mCamera != null) { 
      mPreview.setCamera(null); 
      mCamera.release(); 
      mCamera = null; 
     } 
    } 

    @Override 
    public boolean onCreateOptionsMenu(Menu menu) { 
     //Inflate our menu which can gather user input for switching camera 
     MenuInflater inflater = getMenuInflater(); 
     inflater.inflate(R.menu.camera_menu, menu); 
     return true; 
    } 

    @Override 
    public boolean onOptionsItemSelected(MenuItem item) { 
     //Handle item selection 
     switch (item.getItemId()) { 
      case R.id.switchCam: 
       //Check for availability of multiple cameras 
       if (numberOfCameras == 1) { 
        AlertDialog.Builder builder = new AlertDialog.Builder(this); 
        builder.setMessage(this.getString(R.string.camera_alert)).setNeutralButton("Close", null); 
        AlertDialog alert = builder.create(); 
        alert.show(); 
        return true; 
       } 

       //OK, we have multiple cameras. 
       //Release this camera -> cameraCurrentlyLocked 
       if (mCamera != null) { 
        mCamera.stopPreview(); 
        mPreview.setCamera(null); 
        mCamera.release(); 
        mCamera = null; 
       } 

       //Acquire the next camera and request Preview to reconfigure parameters. 
       mCamera = Camera.open((cameraCurrentlyLocked + 1) % numberOfCameras); 
       cameraCurrentlyLocked = (cameraCurrentlyLocked + 1) % numberOfCameras; 
       mPreview.switchCamera(mCamera); 

       //Start the preview 
       mCamera.startPreview(); 
       return true; 

      case R.id.takePicture: 
       mCamera.takePicture(shutterCallback, rawCallback, jpegCallback); 
       return true; 

      default: 
       return super.onOptionsItemSelected(item); 
     } 
    } 

    /** 
    * Called when shutter is opened 
    */ 
    ShutterCallback shutterCallback = new ShutterCallback() { 
     public void onShutter() { 
     } 
    }; 

    /** 
    * Handles data for raw picture when the picture is taken 
    */ 
    PictureCallback rawCallback = new PictureCallback() { 
     public void onPictureTaken(byte[] data, Camera camera) { 
     } 
    }; 

    /** 
    * Handles data for jpeg picture when the picture is taken 
    */ 
    PictureCallback jpegCallback = new PictureCallback() { 
     public void onPictureTaken(byte[] data, Camera camera) { 
      FileOutputStream outStream = null; 
      try { 
       // Write to SD Card 
       outStream = new FileOutputStream(String.format("/sdcard/%d.jpg", 
       System.currentTimeMillis())); 
       outStream.write(data); 
       outStream.close(); 
      } 
      catch (FileNotFoundException e) { 
       Log.e(TAG, "IOException caused by PictureCallback()", e); 
      } 
      catch (IOException e) { 
       Log.e(TAG, "IOException caused by PictureCallback()", e); 
      } 
     } 
    }; 
} 

Código de clase de vista previa

package assist.core; 

import android.content.Context; 
import android.hardware.Camera; 
import android.hardware.Camera.Size; 
import android.util.Log; 
import android.view.SurfaceHolder; 
import android.view.SurfaceView; 
import android.view.View; 
import android.view.ViewGroup; 

import java.util.List; 
import java.io.IOException; 

/** 
* 
* @author cmetrolis 
*/ 
class Preview extends ViewGroup implements SurfaceHolder.Callback { 

    private final String TAG = "Preview"; 
    SurfaceView mSurfaceView; 
    SurfaceHolder mHolder; 
    Size mPreviewSize; 
    List<Size> mSupportedPreviewSizes; 
    Camera mCamera; 

    Preview(Context context) { 
     super(context); 

     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); 
     mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); 
    } 

    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) { 
      Log.e(TAG, "IOException caused by setPreviewDisplay()", exception); 
     } 
     Camera.Parameters parameters = camera.getParameters(); 
     parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height); 
     requestLayout(); 

     camera.setParameters(parameters); 
    } 

    /** 
    * Called to determine the size requirements for this view and all of its children. 
    * @param widthMeasureSpec 
    * @param heightMeasureSpec 
    */ 
    @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. 
     final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec); 
     final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec); 
     setMeasuredDimension(width, height); 

     if(mSupportedPreviewSizes != null) { 
      mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height); 
     } 
    } 

    /** 
    * Called when this view should assign a size and position to all of its children. 
    * @param changed 
    * @param l 
    * @param t 
    * @param r 
    * @param b 
    */ 
    @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) { 
       previewWidth = mPreviewSize.width; 
       previewHeight = mPreviewSize.height; 
      } 

      // 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); 
      } 
     } 
    } 

    /** 
    * This is called immediately after the surface is first created 
    * @param holder 
    */ 
    public void surfaceCreated(SurfaceHolder holder) { 
     try { 
      if(mCamera != null) { 
       mCamera.setPreviewDisplay(holder); 
      } 
     } 
     catch (IOException e) { 
      Log.e(TAG, "IOException caused by setPreviewDisplay()", e); 
     } 
    } 

    /** 
    * This is called immediately before a surface is being destroyed 
    * @param holder 
    */ 
    public void surfaceDestroyed(SurfaceHolder holder) { 
     //Surface will be destroyed when we return, so stop the preview. 
     if(mCamera != null) { 
      mCamera.stopPreview(); 
      mCamera.release(); 
     } 
    } 

    /** 
    * This is called immediately after any structural changes (format or size) have been made to the surface 
    * @param holder 
    * @param format 
    * @param w 
    * @param h 
    */ 
    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { 
     Camera.Parameters parameters = mCamera.getParameters(); 
     parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height); 
     mCamera.setDisplayOrientation(90); 
     requestLayout(); 

     mCamera.setParameters(parameters); 
     mCamera.startPreview(); 
    } 

    /** 
    * Returns the best preview size 
    * @param sizes 
    * @param w 
    * @param h 
    * @return Size 
    */ 
    private Size getOptimalPreviewSize(List<Size> sizes, int w, int h) { 
     final double ASPECT_TOLERANCE = 0.1; 
     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; 
    } 
} 

código camer_menu.xml

<?xml version="1.0" encoding="utf-8"?> 
<menu xmlns:android="http://schemas.android.com/apk/res/android" 
    android:orientation="vertical" 
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent"> 

    <item android:id="@+id/switchCam" 
      android:title="@string/switch_cam" /> 

    <item android:id="@+id/takePicture" 
      android:title="@string/take_picture" 
      android:onClick="snapPicture" 
      android:layout_gravity="center" /> 
</menu> 

ACTUALIZACIÓN

He intentado cambiar el código en el constructor Vista previa a lo siguiente.

ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT); 
this.setLayoutParams(lp); 

mSurfaceView = new SurfaceView(context); 
mSurfaceView.setLayoutParams(lp); 
addView(mSurfaceView); 

Esto no se colgó, pero tampoco hizo que la cámara tenga pantalla completa.

+0

Hola, soy preguntan si usted ha tenido este problema también: http://stackoverflow.com/questions/16727836/camera-display-preview-full-screen-does-not-maintain-aspect-ratio-image-is-s? – Paul

Respuesta

10

me fijo quitando el siguiente código de la clase de vista previa,

if(mPreviewSize != null) { 
    previewWidth = mPreviewSize.width; 
    previewHeight = mPreviewSize.height; 
} 
1

Dado que está utilizando setContentView con su clase de vista previa personalizada que se deriva de ViewGroup, simplemente pase un ViewGroup.LayoutParams diciéndole que complete su padre.

Algo como esto:

ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT); 
Preview.setLayoutParams(lp); 
+0

Con mi ejemplo no debería ser "this.setLayoutParams (lp)"? – Metropolis

+0

Sí, puedes hacerlo internamente en el constructor de la clase Vista previa, o puedes hacerlo externamente en MainActivity entre instanciarlo y llamar a setContentView – Rich

+0

Intenté poner eso en el constructor Vista previa y cambié "Vista previa" a "esto". Se compila y se ejecuta sin fallar, pero aún no es pantalla completa. Me pregunto si necesito hacer algo con la función "getOptimalPreviewSize" para que esto funcione. – Metropolis

Cuestiones relacionadas