前言
首先看这篇文章之前,要搞懂Captrue的重复模式的基本概念,才会比较好入手。
关键代码
其实相机的缩放最主要的代码并不多,说白了也就是三行代码。
float maxZoom = mCameraCharacteristics.get(CameraCharacteristics.SCALER_AVAILABLE_MAX_DIGITAL_ZOOM);
Rect rect = mCameraCharacteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);
mPreviewRequestBuilder.set(CaptureRequest.SCALER_CROP_REGION, zoomRect);
第一行代码是获取相机设备最大能聚焦的数值,第二行代码是获取相机显示捕获光线的区域,简单来说就是自定义相机的预览画面大小。而第三行这是最核心的代码,第一条与第二条代码都是为了求出zoomRect而服务使用的。zoomRect代表的是缩放后的显示捕获光线的区域。我们只要求出zoomRect便能实现缩放功能。
代码实现
首先我们观察自己手机的相机,采取的是监听触摸两指的缩放进行焦距的调整,我们可以模仿其做一个,首先我们可以监听一下触摸事件。我采用的是fragment,直接在createview上进行监听。
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
Log.d(TAG, "onCreateView: success");
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_take_photo, container, false);
initView(view);
view.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getPointerCount() == 2) {
//表示检测到两个触摸点的时候,执行操作
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_POINTER_DOWN:
//按下的时候,记录原本的位置
float x = event.getX(0) - event.getX(1);
float y = event.getY(0) - event.getY(1);
oldlength = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
break;
case MotionEvent.ACTION_MOVE:
//移动的时候
float newx = event.getX(0) - event.getX(1);
float newy = event.getY(0) - event.getY(1);
double newlength = Math.sqrt(Math.pow(newx, 2) + Math.pow(newy, 2));
System.out.println("对比一下");
System.out.println(oldlength+":"+newlength);
if (newlength >= oldlength) {
//放大操作
previewZoom(true);
} else {
//缩小操作
previewZoom(false);
}
break;
}
}
return true;
}
});
textureView.setSurfaceTextureListener(textureListener);
//动态授权
getPermission();
isCreated = true;
return view;
}
上述代码主要是实现了监听作用,具体的缩放操作还是在previewZoom方法中进行实现。
private final int MAX_ZOOM = 100; // 放大的最大值,用于计算每次放大/缩小操作改变的大小
private int mZoom = 0; // 缩放
private float mStepWidth; // 每次改变的宽度大小
private float mStepHeight; // 每次改变的高度大小
// 每次切换摄像头计算一次就行,结果缓存到成员变量中
private void initZoomParameter() {
Rect rect = mCameraCharacteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);
Log.d(TAG, "sensor_info_active_array_size: " + rect);
// max_digital_zoom 表示 active_rect 除以 crop_rect 的最大值
float max_digital_zoom = mCameraCharacteristics.get(CameraCharacteristics.SCALER_AVAILABLE_MAX_DIGITAL_ZOOM);
Log.d(TAG, "max_digital_zoom: " + max_digital_zoom);
// crop_rect的最小宽高
float minWidth = rect.width() / max_digital_zoom;
float minHeight = rect.height() / max_digital_zoom;
// 因为缩放时两边都要变化,所以要除以2
mStepWidth = (rect.width() - minWidth) / MAX_ZOOM / 2;
mStepHeight = (rect.height() - minHeight) / MAX_ZOOM / 2;
}
public void handleZoom(boolean isZoomIn) {
if (mCameraDevice == null || mCameraCharacteristics == null || mPreviewRequestBuilder == null) {
return;
}
if (isZoomIn && mZoom < MAX_ZOOM) { // 放大
mZoom++;
} else if (mZoom > 0) { // 缩小
mZoom--;
}
Log.v(TAG, "handleZoom: mZoom: " + mZoom);
Rect rect = mCameraCharacteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);
int cropW = (int) (mStepWidth * mZoom);
int cropH = (int) (mStepHeight * mZoom);
Rect zoomRect = new Rect(rect.left + cropW, rect.top + cropH, rect.right - cropW, rect.bottom - cropH);
Log.d(TAG, "zoomRect: " + zoomRect);
mPreviewRequestBuilder.set(CaptureRequest.SCALER_CROP_REGION, zoomRect);
startPreview(); // 需要重新 start preview 才能生效
}
接下来我将对代码中的一些点进行一个讲解。我们在缩放之前还需要计算出每次缩放的步长,而 initZoomParameter方法很明显就是实现这个功能的。可能大部分对最后计算mStepWidth、mStepHeight存在疑问,为什么要减去最小的宽高,为什么要除以2,这些其实画出画的话会好理解很多。
其他的应该没有什么特别难理解的了,实现的过程牢记重复模式的一些点便可以实现。同样的道理,实现录像缩放,拍照缩放便可以解决。