上一篇大概介绍了photoView的touch事件的传递,写的惨不忍睹,也比较简单,想要理解还是得去看源码;这一篇主要介绍下其中对fling事件的分析,顾名思义,就是当图片放大之后,单手快速一滑动,图片会有个惯性移动,而在photoView中,就是在onFling方法中处理的。
源码长这样:
@Override
public void onFling(float startX, float startY,float velocityX,float velocityY) {
ImageView imageView = getImageView();
mCurrentFlingRunnable = new FlingRunnable(imageView.getContext());
mCurrentFlingRunnable.fling(getImageViewWidth(imageView),getImageViewHeight(imageView), (int) velocityX, (int) velocityY);
imageView.post(mCurrentFlingRunnable);
}
我们可以看到这里有个FlingRunnable这个东西,目测就是执行那个惯性运动的动画。详细一看
public FlingRunnable(Context context) {
mScroller = ScrollerProxy.getScroller(context);
}
构造里面有个scoller,应该就是靠他执行滚动的事件,首先执行了该runnable里的fling方法:
public void fling(int viewWidth, int viewHeight, int velocityX,
int velocityY) {
final RectF rect = getDisplayRect();
if (null == rect) {
return;
}
final int startX = Math.round(-rect.left);
final int minX, maxX, minY, maxY;
if (viewWidth < rect.width()) {
minX = 0;
maxX = Math.round(rect.width() - viewWidth);
} else {
minX = maxX = startX;
}
final int startY = Math.round(-rect.top);
if (viewHeight < rect.height()) {
minY = 0;
maxY = Math.round(rect.height() - viewHeight);
} else {
minY = maxY = startY;
}
mCurrentX = startX;
mCurrentY = startY;
if (startX != maxX || startY != maxY) {
mScroller.fling(startX, startY, velocityX, velocityY, minX,
maxX, minY, maxY, 0, 0);
}
}
这里面处理了我们可以fling的范围,设置在我们scroller里面,比如他的x范围,通过放大后的RectF 和实际imageview的大小算出范围。
public void run() {
if (mScroller.isFinished()) {
return; // remaining post that should not be handled
}
ImageView imageView = getImageView();
if (null != imageView && mScroller.computeScrollOffset()) {
final int newX = mScroller.getCurrX();
final int newY = mScroller.getCurrY();
if (DEBUG) {
LogManager.getLogger().d(
LOG_TAG,
"fling run(). CurrentX:" + mCurrentX + " CurrentY:"
+ mCurrentY + " NewX:" + newX + " NewY:"
+ newY);
}
mSuppMatrix.postTranslate(mCurrentX - newX, mCurrentY - newY);
setImageViewMatrix(getDrawMatrix());
mCurrentX = newX;
mCurrentY = newY;
// Post On animation
Compat.postOnAnimation(imageView, this);
}
最后执行runnable这个线程,这里用到了scroller里的知识,不会的同学自行百度;通过:
mSuppMatrix.postTranslate(mCurrentX - newX, mCurrentY - newY);
setImageViewMatrix(getDrawMatrix());
这俩句不断设置新的matrix,声明重绘,我们还看到这里有个
Compat.postOnAnimation(imageView, this);
这里其实是个递归调用,不断调用该runnable,达到连续的绘制过程,代码如下:
public class Compat {
private static final int SIXTY_FPS_INTERVAL = 1000 / 60;
public static void postOnAnimation(View view, Runnable runnable) {
if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN) {
postOnAnimationJellyBean(view, runnable);
} else {
view.postDelayed(runnable, SIXTY_FPS_INTERVAL);
}
}
@TargetApi(16)
private static void postOnAnimationJellyBean(View view, Runnable runnable) {
view.postOnAnimation(runnable);
}
最后会到view.postOnAnimation(runnable)这句,又重新调用了我们的runnable,知道滚动完毕。