最近在zxing二维码扫描的功能基础上 添加相机的手势调焦 遇到个坑 特此记录
参考了这篇博客http://blog.csdn.net/qq_24531461/article/details/62887658
这个听起来很难,但实际很容易。首先消除一个误解,当对相机进行缩放时,无论手指是在屏幕哪个地方缩放,实际都是以预览的中心进行缩放,因为缩放时相机的角度是没有变的。所以我们只需要知道用户两只手指是在放大还是缩小,然后通过setZoom()
指定缩放程度,应用到相机就好了。
注意不同于触摸对焦,现在我们只需要知道手指是合拢还是张开,不需要知道手指的具体位置。怎么知道手指是合拢还是张开?可惜android并没有提供这个方法,只会告诉我们有两个手指,还告诉手指的坐标;我们可以记下手指之间的间距,如果在手指移动时间距变大,那就是张开,否则就是合拢。
首先是计算手指间距,在CameraPreview
中加入
private static float getFingerSpacing(MotionEvent event) {
float x = event.getX(0) - event.getX(1);
float y = event.getY(0) - event.getY(1);
return (float) Math.sqrt(x * x + y * y);
}
从MotionEvent
中获取两个手指的坐标(提前保证一定有两个手指),然后计算距离,很简单。
判断手指合拢还是张开稍后再说,现在来看在知道是合拢还是张开后,怎么设置缩放。
对于相机来说,缩放程度是介于[0, getMaxZoom()
]之间的,不缩放时值为0,具体数值通过setZoom()
设置,应用到相机就能看到效果了。所以只需要在每次触发设置缩放时,根据是缩小还是放大,将缩放值减1或加1,并应用到相机。对于一次缩放手势,会多次触发设置缩放,这样就形成了一个连续的缩放过程,看起来就像过渡效果了。
在CameraPreview
中加入
private void handleZoom(boolean isZoomIn, Camera camera) {
Camera.Parameters params = camera.getParameters();
if (params.isZoomSupported()) {
int maxZoom = params.getMaxZoom();
int zoom = params.getZoom();
if (isZoomIn && zoom < maxZoom) {
zoom++;
} else if (zoom > 0) {
zoom--;
}
params.setZoom(zoom);
camera.setParameters(params);
} else {
Log.i(TAG, "zoom not supported");
}
}
isZoomSupported()
判断相机是否支持缩放,不支持就不用瞎折腾了。getMaxZoom()
获取最大缩放值,最小值为0不用获取;getZoom()
获取当前缩放值,如果是放大,且当前缩放值不超过最大值,则将当前缩放值加1;如果是缩小,且当前缩放值不小于0,则将当前缩放值减1。最后应用到相机,就完成了整个过程。
先看代码,在CameraPreview
中加入
private float oldDist = 1f;
并将onTouchEvent()
修改为
public boolean onTouchEvent(MotionEvent event) {
if (event.getPointerCount() == 1) {
handleFocus(event, mCamera);
} else {
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_POINTER_DOWN:
oldDist = getFingerSpacing(event);
break;
case MotionEvent.ACTION_MOVE:
float newDist = getFingerSpacing(event);
if (newDist > oldDist) {
handleZoom(true, mCamera);
} else if (newDist < oldDist) {
handleZoom(false, mCamera);
}
oldDist = newDist;
break;
}
}
return true;
}
我们只看两指手势的部分。event.getAction() & MotionEvent.ACTION_MASK
获取手势类别;ACTION_POINTER_DOWN
即为两只手指触摸到屏幕,此时我们通过两只手指的坐标得到手指间距,记录到成员变量oldDist
中;ACTION_MOVE
即为手指在屏幕上移动,对应两只手指正在缩放,缩放过程中每次手指移动都会触发。此时记录新的手指间距为newDist
,并与oldDist
比较,确定缩放类型,调用handleZoom()
进行缩放;相机缩放完成后,将oldDist
赋值为newDist
,作为下一次触发ACTION_MOVE
的基准,这样完成缩放。
整体的思路没有问题 也能够实现 最大的一个坑就是 在自定义的surfaceview中 的camera是应该和 之前初始化的camera保持一致的
如果不一致那么 就会导致画面卡死 camera.autofocus 失败的错误
解决办法 在CameraManager类中 写一个方法 return camera 在自定义的surfaceview中接收 同时要判断好 !null
现在手势调焦反应有点慢 还有待于优化一下。。。
优化完成 你只要把放大缩小的zoom++ zoom-- 改成 zoom=zoom+6 zoom = zoom-6 这样每次增加的不是1 而是6 那么缩放的速度就快了