展讯平台MMX客户要求Camera预览界面的zoom图标不要一直显示,只在用户通过手势操作zoom才显示。需要看着不难理解,但是我没有看过zoom这块的逻辑,还是得从头看起。
首先通过工具定位到zoom图标是一个自定义view,VerticalZoomBar,打开这个文件,1100多行,这样的自定义view显然逻辑就是比较复杂的。
图标具体样式如下:
一个白色圆环外框,里面一个深色的实心半透明的圆,中间是一个文字。
既然是自定义view,那它所有的东西就都是在onDraw方法中绘制的,直接看onDraw
@Override
protected void onDraw(Canvas canvas) {
calculateCurrentOrientationDegree();
// drawBG(canvas);
if (mDrawBackgroundProgress) {
drawProgressBar(canvas);
drawProgressBarTip(canvas);
drawIndicator(canvas);
}
if (mDrawTipCircle) {
if (mZoomType != ZOOM_TYPE.TYPE_SINGLE)
drawLittleCircle(canvas);
drawTipCircle(canvas, getWidth() / 2, getHeight() / 2);
}
}
内容倒是不多,分为两个部分,mDrawBackgroundProgress 和 mDrawTipCircle控制的两部分,这里看到progressBar,但是我们看zoom图标是一个圆形啊,没有进度条相关的内容。因此我们先来关注下面的drawTipCircle方法
private void drawTipCircle(Canvas canvas, float center_x, float center_y) {
canvas.save();
canvas.drawCircle(center_x, center_y, mCenterTipCircleradius + 2, mCenterTipBgCirclePaint);
canvas.drawCircle(center_x, center_y, mCenterTipCircleradius, mCenterTipCirclePaint);
canvas.rotate(-mCurrentDegree, center_x, center_y);
canvas.drawText(getTipString(isShowByOutSideValue?mCurrentOutSideValue:getTipValue(TIP_SHOW_SCALE)), center_x, center_y - (mScaleTextBottom + mScaleTextTop) / 2, mCircleTipTextPaint);
canvas.rotate(mCurrentDegree, center_x, center_y);
canvas.restore();
}
这个方法里面绘制了两个圆和一个text,并且两个圆的Radius也是相差2, 跟我们看到的zoom图标比较接近了,在进一步查看两个圆的Paint参数,颜色也符合,因此确认就是这个方法里面在绘制zoom图标了。
在回到onDraw中,就是mDrawBackgroundProgress 和 mDrawTipCircle两个boolean值在控制onDraw真正的绘制内容。
查找文件中修改这两个值的地方,发现了两个成对出现的方法:startDispearAnimationMotion,startShowAnimationMotion。
case TYPE_DOUBLE:
case TYPE_TRIPLE:
mDrawTipCircle = true;
mDrawBackgroundProgress = false;
break;
这里在交叉设置两个boolean变量,circle与progress是互斥显示的,在追是谁在掉用startShowAnimationMotion,跟到了onTouch方法,那就可能是还有触摸事件,我点了下zoom图标,发现果然由原本的circle样式变成了progress。
原来zoom图标是有两种样式的
并且在通过progressBar设置zoom后,手指松开后,过一小会图标消失
case MotionEvent.ACTION_UP:
postDelayed(dispearAnimaRunnable, 500);
通过dispearAnimationRunnable将progress隐藏掉,回到circle状态。
上述是zoom图标绘制的流程,现在来关注下zoom值,我们在预览界面通过手指放大、缩小,最后会在zoom图标中显示出具体的放大倍数值,这是哪个逻辑控制的呢?
前面我们说过,有个drawTipCircle方法是来绘制circle的zoom图标的
canvas.drawText(getTipString(isShowByOutSideValue?mCurrentOutSideValue:getTipValue(TIP_SHOW_SCALE)), center_x, center_y - (mScaleTextBottom + mScaleTextTop) / 2, mCircleTipTextPaint);
mCurrentOutSideValue 就是最终显示的text,追踪mCurrentOutSideValue的赋值,是在setInitValue方法中得到的,在setInitValue通过打印调用堆栈看到:
02-23 17:09:18.002: D/cyy(8668): setInitValue min = 1.0 ,max = 4.0, currentvalue = 1.8876218 mProgress = 7067 java.lang.Throwable
02-23 17:09:18.002: D/cyy(8668): at com.dream.camera.ui.VerticalZoomBar.setInitValue(VerticalZoomBar.java:345)
02-23 17:09:18.002: D/cyy(8668): at com.dream.camera.ui.VerticalZoomBar.updateZoomValue(VerticalZoomBar.java:365)
02-23 17:09:18.002: D/cyy(8668): at com.dream.camera.ZoomPanel.updateZoomLevel(ZoomPanel.java:75)
02-23 17:09:18.002: D/cyy(8668): at com.android.camera.ui.PreviewOverlay$ZoomProcessor.onScale(PreviewOverlay.java:543)
02-23 17:09:18.002: D/cyy(8668): at android.view.ScaleGestureDetector.onTouchEvent(ScaleGestureDetector.java:374)
02-23 17:09:18.002: D/cyy(8668): at com.android.camera.ui.PreviewOverlay$ZoomGestureDetector.onTouchEvent(PreviewOverlay.java:355)
02-23 17:09:18.002: D/cyy(8668): at com.android.camera.ui.PreviewOverlay.onTouchEvent(PreviewOverlay.java:263)
02-23 17:09:18.002: D/cyy(8668): at android.view.View.dispatchTouchEvent(View.java:14399)
02-23 17:09:18.002: D/cyy(8668): at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3201)
02-23 17:09:18.002: D/cyy(8668): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2814)
02-23 17:09:18.002: D/cyy(8668): at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3201)
02-23 17:09:18.002: D/cyy(8668): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2814)
02-23 17:09:18.002: D/cyy(8668): at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3201)
02-23 17:09:18.002: D/cyy(8668): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2814)
02-23 17:09:18.002: D/cyy(8668): at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3201)
02-23 17:09:18.002: D/cyy(8668): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2814)
02-23 17:09:18.002: D/cyy(8668): at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3201)
02-23 17:09:18.002: D/cyy(8668): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2814)
02-23 17:09:18.002: D/cyy(8668): at com.android.internal.policy.DecorView.superDispatchTouchEvent(DecorView.java:491)
02-23 17:09:18.002: D/cyy(8668): at com.android.internal.policy.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1871)
02-23 17:09:18.002: D/cyy(8668): at android.app.Activity.dispatchTouchEvent(Activity.java:4188)
02-23 17:09:18.002: D/cyy(8668): at com.android.camera.CameraActivity.dispatchTouchEvent(CameraActivity.java:1960)
02-23 17:09:18.002: D/cyy(8668): at com.android.internal.policy.DecorView.dispatchTouchEvent(DecorView.java:449)
在预览上的手势是通过PreviewOverlay传递过来的。
public void setInitValue(float minValue, float maxValue, float currentValue)
至此VerticalZoomBar这个自定义view的流程基本看完了。