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