PullToRefreshScrollView下拉刷新开源组件分析

该库被使用较多,而其manual又较为简单。所以决定分析一下,先从几个问题入手:

icon怎么做到随着下拉的进行而联动旋转的?

通过关系图发现我们所有用到的组件都继承自PullToRefreshBase
对,它就是分析的出发点:

1. 类PullToRefreshBase

onTouchEvent(MotionEvent event) –MotionEvent.ACTION_MOVE – >
pullEvent()

newScrollValue = Math.round(Math.min(initialMotionValue - lastMotionValue, 0) / FRICTION);
                itemDimension = getHeaderSize();

看的出,将初始位置减去当前移动到的位置 得到位置增量 再除一个摩擦系数(FRICTION),接着

float scale = Math.abs(newScrollValue) / (float) itemDimension;
/* 中间省略一些代码 */
mHeaderLayout.onPull(scale);

通过header和footer的宽/高度来计算得到一个scale,并调用mHeaderLayout的方法。

注:
1.如果对 PullToRefreshScrollView组件中的xml参数有疑问,一定要看看PullToRefreshBase.init(Context context, AttributeSet attrs)中利用这些参数都干了些啥。

2. LoadingLayout?

在PullToRefreshBase.createLoadingLayout()方法会根据传递的参数(flip or rotate)来创建相应的LoadingLayout,LoadingLayout其有两个子类:RotateLoadingLayout 和 FlipLoadingLayout 分别代表了两种下拉时候所执行的动画所在,这个时候基本上有谱了。

下来将1.说的地方串联起来 ,mHeaderLayout从怎么产生的?

PullToRefreshBase.init()–>createLoadingLayout() –>AnimationStyle.createLoadingLayout()–>RotateLoadingLayout or FlipLoadingLayout.

也就是mHeaderLayout 就是 RotateLoadingLayout or FlipLoadingLayout的对象。

下拉时默认的动画如何替换为自己定义的

以RotateLoadingLayout为例,只需要在两处地方替换自己的实现就可以了。

public class RotateLoadingLayout extends LoadingLayout {

    static final int ROTATION_ANIMATION_DURATION = 1200;

    private final Animation mRotateAnimation;
    private final Matrix mHeaderImageMatrix;

    private float mRotationPivotX, mRotationPivotY;

    private final boolean mRotateDrawableWhilePulling;

    public RotateLoadingLayout(Context context, Mode mode, Orientation scrollDirection, TypedArray attrs) {
        super(context, mode, scrollDirection, attrs);

        mRotateDrawableWhilePulling = attrs.getBoolean(R.styleable.PullToRefresh_ptrRotateDrawableWhilePulling, true);

        mHeaderImage.setScaleType(ScaleType.MATRIX);
        mHeaderImageMatrix = new Matrix();
        mHeaderImage.setImageMatrix(mHeaderImageMatrix);
        /** * mRotateAnimation 是在手下拉结束后 加载中的动画效果, * 可以替换为自己的动画 */
        mRotateAnimation = new RotateAnimation(0, 720, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
                0.5f);
        mRotateAnimation.setInterpolator(ANIMATION_INTERPOLATOR);
        mRotateAnimation.setDuration(ROTATION_ANIMATION_DURATION);
        mRotateAnimation.setRepeatCount(Animation.INFINITE);
        mRotateAnimation.setRepeatMode(Animation.RESTART);
    }

    public void onLoadingDrawableSet(Drawable imageDrawable) {
        if (null != imageDrawable) {
            mRotationPivotX = Math.round(imageDrawable.getIntrinsicWidth() / 2f);
            mRotationPivotY = Math.round(imageDrawable.getIntrinsicHeight() / 2f);
        }
    }

    protected void onPullImpl(float scaleOfLayout) {
        /** * 这个函数里是下拉过程中的联动动画, * 这里根据scaleOfLayout提供的值来在不同阶段展现不同的效果动画 */
        float angle;
        if (mRotateDrawableWhilePulling) {
            angle = scaleOfLayout * 90f;
        } else {
            angle = Math.max(0f, Math.min(180f, scaleOfLayout * 360f - 180f));
        }

        mHeaderImageMatrix.setRotate(angle, mRotationPivotX, mRotationPivotY);
        mHeaderImage.setImageMatrix(mHeaderImageMatrix);
    }

    @Override
    protected void refreshingImpl() {
        mHeaderImage.startAnimation(mRotateAnimation);
    }

    @Override
    protected void resetImpl() {
        mHeaderImage.clearAnimation();
        resetImageRotation();
    }

    private void resetImageRotation() {
        if (null != mHeaderImageMatrix) {
            mHeaderImageMatrix.reset();
            mHeaderImage.setImageMatrix(mHeaderImageMatrix);
        }
    }

    @Override
    protected void pullToRefreshImpl() {
        // NO-OP
    }

    @Override
    protected void releaseToRefreshImpl() {
        // NO-OP
    }

    @Override
    protected int getDefaultDrawableResId() {
        return R.drawable.default_ptr_rotate;
    }

}

你可能感兴趣的:(PullToRefreshScrollView下拉刷新开源组件分析)