2013-06-13 3 views
2

일부 아이콘이있는 맞춤형 카메라 앱을 개발해야합니다.가로 세로 비율이 줄선 사용자 정의 안드로이드 카메라 미리보기

내 첫 번째 시도는 Android 카메라 가이드를 따라했습니다. 그리고 아이콘이 잘 작동해도 화면 비율이 잘못되었습니다. 미리보기에서 이미지가 흐릿 해 보였습니다. 그래서 나는 많은 것을 연구했고 선호하는 크기에 대해 시도한 것들 중 아무 것도 작동하지 않는 것처럼 보였습니다. 항상 미리보기 크기가 늘어났습니다.

그러면 카메라의 APIDemos 코드 (이 질문 덕분에 https://stackoverflow.com/a/12751221/1555573 덕분에)를 검토해 보았습니다. 완벽하게 작동했습니다. 아이디어는 나의 첫 번째 접근 방식과 조금 다르지만 작동합니다.

이 예제와 솔루션은 매우 간단하며 카메라 만 보여주는 것이 문제입니다. 아이디어는 CameraPreview가 ViewGroup이기도하고 레이아웃 파일을 사용하지 않고 Activity의 contentView로 프로그래밍 방식으로 추가된다는 것입니다.

카메라 또는 측면에 일부 아이콘 (ImageButton)을 추가하려면이 예제를 수정해야합니다 (예를 들어 카메라 미리보기가 가운데에 표시되지만 수정하지 않아도됩니다). 한쪽) ?

/* 
* Copyright (C) 2007 The Android Open Source Project 
* 
* Licensed under the Apache License, Version 2.0 (the "License"); 
* you may not use this file except in compliance with the License. 
* You may obtain a copy of the License at 
* 
*  http://www.apache.org/licenses/LICENSE-2.0 
* 
* Unless required by applicable law or agreed to in writing, software 
* distributed under the License is distributed on an "AS IS" BASIS, 
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
* See the License for the specific language governing permissions and 
* limitations under the License. 
*/ 

package com.example.android.apis.graphics; 

import android.app.Activity; 
import android.app.AlertDialog; 
import android.content.Context; 
import android.hardware.Camera; 
import android.hardware.Camera.CameraInfo; 
import android.hardware.Camera.Size; 
import android.os.Bundle; 
import android.util.Log; 
import android.view.Menu; 
import android.view.MenuInflater; 
import android.view.MenuItem; 
import android.view.SurfaceHolder; 
import android.view.SurfaceView; 
import android.view.View; 
import android.view.ViewGroup; 
import android.view.Window; 
import android.view.WindowManager; 

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

// Need the following import to get access to the app resources, since this 
// class is in a sub-package. 
import com.example.android.apis.R; 

// ---------------------------------------------------------------------- 

public class CameraPreview extends Activity { 
    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.switch_cam: 
      // 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; 
     default: 
      return super.onOptionsItemSelected(item); 
     } 
    } 
} 

// ---------------------------------------------------------------------- 

/** 
* 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's display. 
*/ 
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); 
    } 

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

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

    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) { 
      Log.e(TAG, "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 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; 
    } 

    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. 
     Camera.Parameters parameters = mCamera.getParameters(); 
     parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height); 
     requestLayout(); 

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

} 

내가 카메라에 대한 안드로이드 코드의 일부 연구를하려고했지만 정말 복잡하고 나는이에 대한 몇 가지 간단한 해결책을 찾기 위해 기대했다 ... :

현재의 코드는 하나입니다 누구든지 내가 필요로하는 것과 비슷한 기능을하는 앱을 가지고 있습니까?

+0

나는 동일한 문제에 직면 해있다. 해결 했니? – jagdish

답변

1

예 카메라 뷰에 하나의 FrameLayout을 추가하여 카메라에 아이콘을 추가 할 수 있습니다. FrameLayout 배경에 아이콘을 설정하거나 FrameLayout 내에서 다른 ImageView를 가져 와서 ImageView의 배경을 설정할 수 있습니다.

+0

좀 더 명확히 할 수 있습니까? FrameLayout을 어디에 추가 했습니까? –

관련 문제