预览会出现拉伸的问题代码:
预览拉伸Demo
预览画面拉伸问题改正的 gitee 代码在文章最后给出
预览拉伸的原因:
每颗Camera都支持一些分辨率,Camera的这些图像如果和预览画面的宽高比例不一致就会发生预览图像拉伸。注意这里是宽高比,只要宽高比一致,即使宽高的大小不一样也不会拉伸。
另外:旋转手机时预览画面拉伸非常严重。
预览拉伸的解决办法:
将预览画面的宽高比设置为和 Camera 输出画面的宽高比一致
步骤:
1.列出这颗 Camera 支持的所有 Size,以及手机的 width 和 height
2.遍历选择一个 Size,算出这个 Size 的宽高比 ratio = size.height / size.width(因为Camera Size的宽高是相反的)
3.以手机的宽作为预览控件的宽,如果得出的 ratio 使得控件的 height 超过手机的 height ,那么 遍历下一个Size 重复步骤2,直到选出一个合适的 Size。如果所有的 Size 的高都比手机的高都大,那么就需要使用 Matrix 手动将 Camera 输出的画面缩放到一个合适的大小,最后这种情况先不实现。
两点注意:
1.Camera 支持的所有 Size ,它的 size.width 和 size.height 是反着的,我们要把 size.width 当成高 ,size.height 当成宽。
2.预览控件在设置宽高比的时候,要保证预览画面的宽和手机的宽是一样的,这样看起来才不别扭。
预览控件的宽应该设置为 match_parent,高应该设置为 wrap_content
假设要设置的宽高比 ratio = cameraWidth / cameraHeight,
预览控件在设置宽高比的时候只改变高度即可: height = width / ratio
也许你会发现,这里我们并没有针对横屏的预览显示做处理,实际测试中发现,我们设置完宽高比,在旋转到横屏的时候也不会发生预览拉伸。
关键代码:
private Size getBestSize() {
CameraManager cameraManager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
CameraCharacteristics characteristics = null;
try {
characteristics = cameraManager.getCameraCharacteristics("0");
} catch (CameraAccessException e) {
e.printStackTrace();
}
// 获得手机的宽高
Point point = new Point();
((Activity) context).getWindowManager().getDefaultDisplay().getRealSize(point);
int phone_width = point.x;
int phone_height = point.y;
Log.e(TAG, "phone_width = "+phone_width+", phone_height = "+phone_height );
// 获取这颗Camera支持的Size
StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
ArrayList<Size> sizeList = new ArrayList<Size>(Arrays.asList(map.getOutputSizes(SurfaceTexture.class)));
for (Size size : sizeList) {
Log.e(TAG, "width = "+size.getWidth() +", height = "+size.getHeight());
double ratio = (double) size.getHeight() / (double)size.getWidth();
// 以手机的宽作为控件的宽,计算出控件的高
int height = (int) (phone_width / ratio);
Log.e(TAG, "ratio = " + ratio + ", height = " + height);
// 如果计算出的控件的高超过手机的高,就遍历下一个
if (height > phone_height) {
continue;
}
else {
return size;
}
}
// 没有合适的宽高比
return null;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.TextureView;
public class AutoFitTextureView extends TextureView {
private static final String TAG = "hugang";
private int ratioW = 0;
private int ratioH = 0;
public AutoFitTextureView(Context context) {
super(context);
}
public AutoFitTextureView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public AutoFitTextureView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
/**
* 设置宽高比
* @param width
* @param height
*/
public void setAspectRation(int width, int height){
if (width < 0 || height < 0) {
throw new IllegalArgumentException("width or height can not be negative.");
}
ratioW = width;
ratioH = height;
Log.e(TAG, "setAspectRation: ratioW = "+ratioW+" ratioH = "+ratioH );
//请求重新布局
requestLayout();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
Log.e(TAG, "onMeasure: width = "+width+" height = "+height );
if (0 == ratioW || 0 == ratioH){
//未设定宽高比,使用预览窗口默认宽高,当AutoFitTextureView初始化的时候会走一次这个逻辑
setMeasuredDimension(width, height);
Log.e(TAG, "onMeasure 000: width = "+width+" height = "+height );
} else {
//设定宽高比,调整预览窗口大小(调整后窗口大小不超过默认值)
if (width < height * ratioW / ratioH) {
Log.e(TAG, "onMeasure 111: width = "+width+" height = "+(width * ratioH / ratioW) );
setMeasuredDimension(width, width * ratioH / ratioW);
} else {
Log.e(TAG, "onMeasure 222: width = "+(height * ratioW / ratioH)+" height = "+height );
setMeasuredDimension(height * ratioW / ratioH, height);
}
}
}
}
解决预览画面拉伸的Demo
预览画面拉伸问题改正Demo