PhotoView源码解析 Part I

最近需要用到一个类似微信图片的查看缩放功能,PhotoView本身的功能不太够用。于是将PhotoView的源码本地化,先读懂,再修改。对于android新人来说学到了不少东西。在这里做一下积累,以免以后忘记。
向下继续阅读请集成好PhotoView类库配合使用。

PhotoView库的核心类是PhotoViewAttacher,而他由几个核心构建构成。我们一个个拆开来看。

OnTouchListener

从监听事件这些驱动部件来入手容易一些。对于代码的解释我直接放在注释里。

@Override
public boolean onTouch(View view, MotionEvent event) {
    boolean handled = false;
    //先判断是否启用了缩放,view的drawable是否不为空
    if (mZoomEnabled && ((ImageView) view).getDrawable() != null) {
        switch (event.getAction()) {
            //当用户的第一根手指触碰到我们的view的时候
            case MotionEvent.ACTION_DOWN:
                ViewParent parent = view.getParent();
                if (parent != null) {
                    parent.requestDisallowInterceptTouchEvent(true);
                }
                //取消左右翻页动画
                cancelFling();
                //MotionEvent.ACTION_DOWN中没有什么具体操作,我们看一下MotionEvent.ACTION_UP
                break;
            case MotionEvent.ACTION_CANCEL:
                //当用于最后一根手指离开view的时候
            case MotionEvent.ACTION_UP:
                //判断当前的缩放比例是否小于约定的最小缩放比例
                if (getScale() < DEFAULT_MIN_SCALE) {
                    //获取当前正在展示的矩形
                    RectF rect = getDisplayRect();
                    if (rect != null) {
                        //矩形不为空则 调用缩放动画
                        view.post(new AnimatedZoomRunnable(getScale(), DEFAULT_MIN_SCALE,
                                rect.centerX(), rect.centerY()));
                        handled = true;
                    }
                }
                break;
        }

阅读完以上内容可得知,手指抬起时调用这个缩放动画,那就直接看这个AnimatiedZoomRunnable类中查看。不看代码,直接debug,或者打log看代码调用情况就可以知道,

private class AnimatedZoomRunnable implements Runnable {
    private final float mFocalX, mFocalY;
    private final long mStartTime;
    private final float mZoomStart, mZoomEnd;

    public AnimatedZoomRunnable(final float currentZoom, final float targetZoom,
                                final float focalX, final float focalY) {
        //从上面传入的数据可以得知这些参数的作用
        //矩形中心的横坐标
        mFocalX = focalX;
        //矩形中心的纵坐标
        mFocalY = focalY;
        //动画开启时的时间戳
        mStartTime = System.currentTimeMillis();
        //动画开始前 矩形的比例
        mZoomStart = currentZoom;
        //动画完成时想要到达的比例
        mZoomEnd = targetZoom;
    }

    @Override
    public void run() {
   		//先直接去看interpolate()方法
        float t = interpolate();
        //所以我自己的代码中直接为t 改了个名字 叫 progressPercent (进度百分比)
        //当前应该缩放到的比例 = 原本的缩放比例 + 缩放进度百分比 x 需要缩放的全部的量  
        float scale = mZoomStart + t * (mZoomEnd - mZoomStart);
        // 当前需要缩放的比例 = 当前需要缩放到的比例 / 当前比例
        float deltaScale = scale / getScale();
		//调用 onScale方法
        onScale(deltaScale, mFocalX, mFocalY);
        //这里与前面插值器的内容对应。经历时间超过约定的动画演示时间后,t本身超过1。与1取更小返回1。插值器收到了1这个整数,返回结果也是1。最后这个t得出=1的值,不在循环调用AnimatedZoomRunnable。
        if (t < 1f) {
            Compat.postOnAnimation(mImageView, this);
        }
    }

    private float interpolate() {
    	//首先1f * 计算结果的作用就是强转为float精度,效果与 (float)相同
    	//返回去查看mZoomDuration是约定好的缩放时间,所以PhotoView中设定的自动缩放动画无论比例大小都是相同时间完成的。
    	//所以这个参数t实际得到的是当前缩放动画应该完成到哪个阶段的百分比,也可以说是缩放进度的进度条。
        float t = 1f * (System.currentTimeMillis() - mStartTime) / mZoomDuration;
        //下面这两句的作用实际是插值器,插值器是类似一种中间帧的概念,让本身速度不变的变化有了变化的节奏。PhotoView的作者采用的是 先加速后减速插值器。详细内容可以参考下面的网址,看我就能懂了
        //	https://blog.csdn.net/xiaochuanding/article/details/73200149
        //与1取更小 是因为 获得的时间t是有时间间隔的,getInterpolation(t)如果不传入整数,他就会拿去继续插值,不会返回1。知道有一次碰巧t获取了一个整数值并传入。getInterpolation(t)才会传一个1回来。
        //我之前测试过如果 Math.min(1.1f,t);与1.1来取最小,这样就永远返回不来整数,那这个插值器就不会永远返回不了1了。
        t = Math.min(1f, t);
        t = mInterpolator.getInterpolation(t);
        //其实上面这两行直接删掉也没有什么不妥,个人认为短短200毫秒的动画变化,正常人也看不出来什么区别。
        return t;
    }
}

你可能感兴趣的:(PhotoView源码解析 Part I)