相機(jī)在調(diào)用過(guò)程中需要設(shè)置預(yù)覽尺寸(分辨率)(640 * 480、1920 * 1080等),同時(shí)需要設(shè)置一個(gè)控件去渲染畫面,這個(gè)控件可以是ImageView、TextureView也可以是SurfaceView。一般常見(jiàn)的預(yù)覽尺寸比例是4:3、16:9等,但在開發(fā)時(shí)界面上給的預(yù)覽窗口一般不會(huì)是這些比例,這時(shí)如果不做處理,預(yù)覽畫面鋪面整個(gè)窗口時(shí)就會(huì)出現(xiàn)拉伸或者縮小的情況。
這里給出兩種解決方法:
1、通過(guò)Matrix對(duì)每一幀圖片做縮放、移動(dòng)等操作,然后通過(guò)Canvas繪制到渲染容器里。
偽代碼:
數(shù)據(jù)幀回調(diào) ->{
val bitmap = 從每一幀數(shù)據(jù)中獲取Bitmap
val canvas = 從TextureView或者SurfaceView中獲取Canvas
/*bitmap的尺寸已知即初始化相機(jī)參數(shù)時(shí)設(shè)定的分辨率(640 * 480、1920 * 1080等)
*通過(guò)bitmap的寬高尺寸和控件的寬高尺寸算出bitmap的縮放比例ratio
*計(jì)算ratio根據(jù)最小寬度計(jì)算(類似于屏幕適配里的一種方案)
*最小寬度計(jì)算:以4:3出圖為例(分辨率為640 * 480),
*假如此時(shí)控件的寬度為1600px,那么按4:3的寬高比計(jì)算高度應(yīng)該不低于1200px,
*如果實(shí)際高度小于了1200px,那么就應(yīng)該以實(shí)際控件高度去計(jì)算出對(duì)應(yīng)的寬度,
*確定了bitmap應(yīng)該渲染出的寬高就算出來(lái)縮放比ratio。
*/
matrix: Matrix
if(第一幀數(shù)據(jù)){
val scaleRatio = if (viewWidth>以viewHeight和寬高比例計(jì)算出的寬度)viewHeight/bitmapHeight else viewWidth/bitmapWidth
matrix.postScale(scaleRatio,scaleRatio)//寬高等比縮放
//圖片進(jìn)行了縮放,不能充滿整個(gè)渲染容器,通過(guò)位移操作將圖片置于容器中心
matrix.postTranslate(if(以寬度計(jì)算)0f else(viewWidth-(viewHeight*bitmapWidth/bitmapHeight)/2),if(以寬度計(jì)算) (viewHeight-(viewWidth*bitmapHeight/bitmapWidht)/2) else 0f)
}
canvas.drawBitmap(bitmap,matrix,paint)
}
2、自定義TextureView或者SurfaceView,通過(guò)外部設(shè)置的寬高比重新計(jì)算控件尺寸,重寫onMeasure()函數(shù)。
AspectRatioSurfaceView :SurfaceView{
setRatio(width,height){
//設(shè)置寬高比,還是以最小寬度原則去評(píng)定是以寬度計(jì)算還是高度計(jì)算
if(getWidth()>getHeight()*width/height) 以高度計(jì)算 else 以寬度計(jì)算
重繪布局
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int){
if(以高度計(jì)算)setMeasuredDimension(getHeight()*width/height,getHeight())
else setMeasuredDimension(getWidth(),getWidth()*heigth/width)
}
}
上述兩種方法只是基于設(shè)備處于一個(gè)橫豎屏不變的情況下寫的,如果有橫豎屏切換的場(chǎng)景,還需要獲取設(shè)備方向然后動(dòng)態(tài)調(diào)整。