Android Camera多屏幕適配解決預覽照片拉伸

一般,拍照預覽頁面的照片拉伸主要與下面兩個因素有關:

1.     Surfaceview的大小android

2.     Camera中的Preview的大小ide

以下圖:

    圖中preview顯示的是手機支持的預覽尺寸,picture顯示的是手機支持設置圖片尺寸,screen顯示的是屏幕尺寸,surface顯示的是surfaceview尺寸,default pre:手機缺省狀況下的預覽尺寸,default pic:手機缺省請款下的圖片尺寸。reqPreview:手機設置的預覽尺寸,reqPicSize:手機設置的圖片尺寸。
 

 

如圖,該手機surfaceview大小爲1280*720(橫屏,比例爲:16:9)預覽尺寸大小爲960*720(橫屏,比例爲4:3)。從上面的二維碼能夠看到產生了明顯的拉伸。正由於surfaceview的寬高比例跟camera preview的寬高比例不同纔會產生這樣的效果。post

若是surfaceview尺寸比例跟預覽尺寸比例相同,那便不會產生變形,以下圖:this

 

設置surfaceview大小爲 1280*720(橫屏,比例爲:4:3)預覽尺寸大小爲2048*1152(橫屏,比例爲4:3)便不會拉伸變形。spa

上面只是針對一種屏幕進行設置,並且每臺手機所支持的預覽尺寸是不同的,因此這樣子固定死的話極可能會產生程序崩潰,而崩潰的緣由是由於該手機不支持你所支持的尺寸。.net

 

那麼問題就來了,怎麼樣纔可以達到適配多臺手機,界面不產生拉伸變形,並且程序又不崩潰?

思路以下:code

1.     先將獲取手機支持預覽的尺寸列表經過方法parmeters.getSupportedPreviewSizes()來獲得返回類型爲List<Size>的值,orm

2.     先進行屏幕方向的一個判斷,由於預覽列表裏面的尺寸都是w>h(即橫屏),若是屏幕是豎屏則須要先將寬高進行調換,這樣方便接下來的比較。blog

3.     先用for循環將預覽尺寸列表每一個元素寬高與surfaceview的寬高進行比較,若是存在寬高尺寸都與surfaceview寬高尺寸相同的size則將該寬高設置爲預覽尺寸。圖片

4.     若是步驟2找不到相同尺寸就得進行該步驟,將尺寸列表的寬高比例和surfaceview的比例做比較,找到一個相同或相近的。(通常來講,只要surfaceview的尺寸和屏幕尺寸相同,就能夠找到相同的比例)而後將該尺寸的size設置爲預覽尺寸。

接下來是上代碼

  

/**
     * 經過對比獲得與寬高比最接近的尺寸(若是有相同尺寸,優先選擇)
     * 
     * @param surfaceWidth
     *            須要被進行對比的原寬
     * @param surfaceHeight
     *            須要被進行對比的原高
     * @param preSizeList
     *            須要對比的預覽尺寸列表
     * @return 獲得與原寬高比例最接近的尺寸
     */
    protected Camera.Size getCloselyPreSize(int surfaceWidth, int surfaceHeight,
            List<Size> preSizeList) {
        
        int ReqTmpWidth;
        int ReqTmpHeight;
        // 當屏幕爲垂直的時候須要把寬高值進行調換,保證寬大於高
        if (mIsPortrait) {
            ReqTmpWidth = surfaceHeight;
            ReqTmpHeight = surfaceWidth;
        } else {
            ReqTmpWidth = surfaceWidth;
            ReqTmpHeight = surfaceHeight;
        }
        //先查找preview中是否存在與surfaceview相同寬高的尺寸
        for(Camera.Size size : preSizeList){
            if((size.width == ReqTmpWidth) && (size.height == ReqTmpHeight)){
                return size;
            }
        }
        
        // 獲得與傳入的寬高比最接近的size
        float reqRatio = ((float) ReqTmpWidth) / ReqTmpHeight;
        float curRatio, deltaRatio;
        float deltaRatioMin = Float.MAX_VALUE;
        Camera.Size retSize = null;
        for (Camera.Size size : preSizeList) {
            curRatio = ((float) size.width) / size.height;
            deltaRatio = Math.abs(reqRatio - curRatio);
            if (deltaRatio < deltaRatioMin) {
                deltaRatioMin = deltaRatio;
                retSize = size;
            }
        }

        return retSize;
    }

 

其中 參數 width 和height 是 SurfaceView 的寬和高,能夠在surfaceChanged方法中找到:

package com.yfqsdie.tower.preview;

import com.yfqsdie.tower.util.CameraUtil;

import android.content.Context;
import android.graphics.PixelFormat;
import android.hardware.Camera;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

/**
 * Created by renlei
 * DATE: 15-11-5
 * Time: 下午4:52
 */
public class MySurfacePreview extends SurfaceView implements SurfaceHolder.Callback {
    private SurfaceHolder surfaceHolder;
    private Handler mHandler;

    public MySurfacePreview(Context context, AttributeSet attrs) {
        super(context, attrs);
        surfaceHolder = getHolder();
        surfaceHolder.setFormat(PixelFormat.TRANSPARENT);//translucent半�?�明 transparent透明
        surfaceHolder.addCallback(this);
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        CameraUtil.getInstance().doOpenCamera(Camera.CameraInfo.CAMERA_FACING_BACK);
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        System.out.print("width="+width+" height="+height+" format="+format);
//        CameraUtil.getInstance().doStartPreview(surfaceHolder);
        CameraUtil.getInstance().doStartPreview(surfaceHolder,width,height);  //spire modify 2017-09-27 解決變形問題
        if (mHandler != null) {
            mHandler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    mHandler.sendEmptyMessage(CameraUtil.PREVIEW_HAS_STARTED);
                }
            }, 1000);
        }
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        CameraUtil.getInstance().doStopPreview();
    }

    public void setmHandler(Handler handler) {
        this.mHandler = handler;
    }
}

 

 

 
相關文章
相關標籤/搜索