2015-05-05 23 views
23

Realizzo una fotocamera personalizzata come "SnapChat" per un'app per Android ma l'anteprima della fotocamera è estesa su pochi dispositivi come (Moto g seconda generazione, uno + uno) ma non su (Samsung s3, Samsung s4). Ho usato il seguente riferimento Camera display/preview in full screen does not maintain aspect ratio - image is skewed, stretched in order to fit on the screen. Ma questo non mi aiuta al 100%. Sto condividendo lo schermo.Anteprima fotocamera estesa su pochi dispositivi Android

L'immagine allungata su Samsung Moto G è di seconda generazione. enter image description here enter image description here

immagini Samsung S3 che non si estendevano è al di sopra

private void setPreviewLayout() { 
    if (null == mCamera) { 
     return; 
    } 
    Camera.Parameters parameters = null; 
    Camera.Size size = null; 
    try { 
     int screenWidth = (int) getResources().getDisplayMetrics().widthPixels; 
     int screenHeight = (int) getResources().getDisplayMetrics().heightPixels; 
     parameters = mCamera.getParameters(); 
     size = getOptimalPreviewSize(mCamera.getParameters().getSupportedPreviewSizes(), screenWidth, screenHeight); 
     if (size != null) { 

      parameters.setPreviewSize(size.width, size.height); 

     } 

     parameters.setPictureSize(screenHeight, screenWidth); 
     ; 
     mCamera.setParameters(parameters); 
     if (on && currentCameraId == Camera.CameraInfo.CAMERA_FACING_BACK) { 
      parameters.setFlashMode(Camera.Parameters.FLASH_MODE_ON); 
     } else { 
      parameters.setFlashMode(Camera.Parameters.FLASH_MODE_OFF); 
     } 
     parameters.setWhiteBalance(Camera.Parameters.WHITE_BALANCE_AUTO); 
     parameters.setExposureCompensation(0); 
     parameters.setPictureFormat(ImageFormat.JPEG); 
     parameters.setJpegQuality(100); 
     List<String> focusModes = parameters.getSupportedFocusModes(); 
     if (focusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) { 
      parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE); 
     } else if (focusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) { 
      parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO); 
     } 
     mCamera.setParameters(parameters); 
     /* 
     * camera.setPreviewDisplay(surfaceHolder); camera.startPreview(); 
     */ 

    } catch (Exception e) { 
     e.printStackTrace(); 
    } 

} 
private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) { 
    final double ASPECT_TOLERANCE = 0.1; 
    double targetRatio = (double) h/w; 

    if (sizes == null) 
     return null; 

    Camera.Size optimalSize = null; 
    double minDiff = Double.MAX_VALUE; 

    int targetHeight = h; 

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

    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; 
} 
+0

Qualcuno può aiutarmi? –

risposta

12

utilizzando getOptimalPreviewSize() è importante, ma non risolve tutti che si estende su tutti i dispositivi in ​​tutti i layout. Devi essere preparato a ritagliare l'anteprima un po 'in modo che l'anteprima riempia lo schermo senza distorsioni.

Ci sono diverse tecniche per forzare la dimensione della superficie diversa dalla dimensione effettiva dello schermo, ma questo trovo la più semplice:

aggiungo il CameraView al mio layout:

public class CameraView extends SurfaceView implements SurfaceHolder.Callback { 

public CameraView(Context context, AttributeSet attr) { 
    super(context, attr); 

    // install a SurfaceHolder.Callback so we get notified when the 
    // underlying surface is created and destroyed. 
    getHolder().addCallback(this); 
} 

@Override public void surfaceCreated(SurfaceHolder holder) { 
    openCamera(); 
    bCameraInitialized = false; 
} 

@Override public void surfaceDestroyed(SurfaceHolder holder) { 
    camera.release(); 
} 

@Override public void surfaceChanged(SurfaceHolder holder, 
     int format, int w, int h) { 
     if (bCameraInitialized) { 
      // we will get here after we have resized the surface, see below 
      return; 
     } 
     cameraSetup(w, h); 
     bCameraInitialized = true; 
} 

private void cameraSetup(int w, int h) { 
    // set the camera parameters, including the preview size 

    FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams(); 
    double cameraAspectRatio = ((double)optimalSize.width)/optimalSize.height; 

    if (((double)h)/w > cameraAspectRatio) { 
     lp.width = (int)(h/cameraAspectRatio+0.5); 
     lp.height = h; 
    } 
    else { 
     lp.height = (int)(w*cameraAspectRatio + 0.5); 
     lp.width = w; 
     lp.topMargin = (h - lp.height)/2; 
    } 
    lp.gravity = Gravity.CENTER_HORIZONTAL | Gravity.TOP; 

    setLayoutParams(lp); 
    requestLayout(); 
} 

Per sottolineare l'idea principale, non ho incluso la gestione degli errori, e non ho mostrato qui come la fotocamera is actually started with a secondary Looper.

+0

Ho usato il tuo codice ma questo non risolve il mio problema. Sto usando TextureView.SurfaceTextureListener invece di Surface view. puoi aggiungermi su skype sachin.auxiliumit o darmi il tuo id skype. Ti ringrazierò davvero molto. –

+0

Non sarò disponibile su Skype fino a domani. Credo che anche con TextureView hai ancora gli stessi eventi di layout. Puoi usare 'onMayure()' come spiegato sopra, o 'OnLayoutListener' - tutto ciò che serve è impostare larghezza e altezza fisse per la tua vista, non importa di che tipo - e probabilmente centrarlo nel suo contenitore. –

+0

Grazie mille ................... –

0

provare questo si sta lavorando ...

public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback { 

private static final String TAG = "Camera Preview"; 
private static final double PREVIEW_SIZE_FACTOR = 3.00; 
private SurfaceHolder mHolder = null; 
private Camera mCamera = null; 
Camera.Parameters _parameters=null; 

@SuppressWarnings("deprecation") 
public CameraPreview(Context context, Camera camera) { 
    super(context); 
    mCamera = camera; 
    // Install a SurfaceHolder.Callback so we get notified when the 
    // underlying surface is created and destroyed. 
    mHolder = getHolder(); 
    mHolder.addCallback(this); 
    // deprecated setting, but required on Android versions prior to 3.0 
    mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); 
} 

public void surfaceCreated(SurfaceHolder holder) { 
    // The Surface has been created, now tell the camera where to draw the preview. 
    try { 
     Camera.Parameters parameters = mCamera.getParameters(); 
     final Size mPreviewSize = getOptimalSize(); 
     parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height); 
     requestLayout(); 
     mCamera.setParameters(parameters); 
     mCamera.setPreviewDisplay(holder); 
     mCamera.startPreview(); 
     //startContinuousAutoFocus(); 
    } catch (Exception e) { 
     Log.d(TAG, "Error setting camera preview: " + e.getMessage()); 
    } 
} 
public void surfaceDestroyed(SurfaceHolder holder) { 
} 

@SuppressLint("NewApi") 
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { 
    // If your preview can change or rotate, take care of those events here. 
    // Make sure to stop the preview before resizing or reformatting it. 

    if (mHolder.getSurface() == null){ 
     // preview surface does not exist 
     return; 
    } 

    // stop preview before making changes 
    try { 
     mCamera.stopPreview(); 
    } catch (Exception e){ 
     // ignore: tried to stop a non-existent preview 
    } 

    // set preview size and make any resize, rotate or 
    // reformatting changes here 
    // set Camera parameters 

    // start preview with new settings 
    try { 
     mCamera.setPreviewDisplay(mHolder); 
     mCamera.startPreview(); 

    } catch (Exception e){ 
     Log.d(TAG, "Error starting camera preview: " + e.getMessage()); 
    } 
    } 
public void startPreview(){ 
    try{ 
     mCamera.startPreview(); 
    }catch (Exception e) { 
    } 
     } 
     private Size getOptimalSize() { 
    Camera.Size result = null; 
    final Camera.Parameters parameters = mCamera.getParameters(); 
    Log.i(CameraPreview.class.getSimpleName(), "window width: " + getWidth() + ", height: " + getHeight()); 
    for (final Camera.Size size : parameters.getSupportedPreviewSizes()) { 
     if (size.width <= getWidth() * PREVIEW_SIZE_FACTOR && size.height <= getHeight() * PREVIEW_SIZE_FACTOR) { 
      if (result == null) { 
       result = size; 
      } else { 
       final int resultArea = result.width * result.height; 
       final int newArea = size.width * size.height; 

       if (newArea > resultArea) { 
        result = size; 
       } 
      } 
     } 
    } 
    if (result == null) { 
     result = parameters.getSupportedPreviewSizes().get(0); 
    } 
    Log.i(CameraPreview.class.getSimpleName(), "Using PreviewSize: " + result.width + " x " + result.height); 
    return result; 
} 
} 
+0

Questo non funziona. sto usando TextureView.SurfaceTextureListener invece di surfacecancan mi dici come posso fare. –

+0

Si prega di vedere il mio intero codice sotto –

0

È necessario eseguire l'override del metodo onMeasure di classe SurfaceView per ottenere la larghezza e l'altezza del SurfaceView

@Override 
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 
     final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec); 
     final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec); 
     setMeasuredDimension(width, height); 

     if (mSupportedPreviewSizes != null) { 
      mPreviewSize = getOptimalPreviewSize(mCamera.getParameters().getSupportedPreviewSizes(), width, height); 
     } 
    } 

quindi impostare la dimensione di anteprima che hai alla dimensione dell'anteprima dei parametri della fotocamera.

cameraParameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height); 
mCamera.setParameters(cameraParameters); 

getSuggestedMinimumHeight(), getSuggestedMinimumWidth() sono i metodi della classe View

Spero che questo aiuti !!!

+0

Ciao Lakshay, sto usando TextureView.SurfaceTextureListener invece della vista di superficie. Non ha il metodo onMeasure. puoi dirmi come posso fare. –

+0

Allora, per favore, puoi elaborare il tuo codice?Dovrò vedere come non ho mai usato l'ascoltatore di TextureView discusso – lakshay

+0

Si prega di vedere il mio intero codice sopra –

Problemi correlati