1. 程式人生 > >Android Camera多螢幕適配解決預覽照片拉伸

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

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

1.     Surfaceview的大小

2.     Camera中的Preview的大小

如下圖:

    圖中preview顯示的是手機支援的預覽尺寸,picture顯示的是手機支援設定圖片尺寸,screen顯示的是螢幕尺寸,surface顯示的是surfaceview尺寸,default pre:手機預設情況下的預覽尺寸,default pic:手機預設請款下的圖片尺寸。reqPreview:手機設定的預覽尺寸,reqPicSize:手機設定的圖片尺寸。

 

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

如果surfaceview尺寸比例跟預覽尺寸比例相同,那便不會產生變形,如下圖:


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

上面只是針對一種螢幕進行設定,而且每臺手機所支援的預覽尺寸是不一樣的,所以這樣子固定死的話很可能會產生程式崩潰,而崩潰的原因是因為該手機不支援你所支援的尺寸。

那麼問題就來了,怎麼樣才能夠達到適配多臺手機,介面不產生拉伸變形,而且程式又不崩潰?

思路如下:

1.     先將獲取手機支援預覽的尺寸列表通過方法parmeters.getSupportedPreviewSizes()來得到返回型別為List<Size>的值,

2.     先進行螢幕方向的一個判斷,因為預覽列表裡面的尺寸都是w>h(即橫屏),如果螢幕是豎屏則需要先將寬高進行調換,這樣方便接下來的比較。

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