该库被使用较多,而其manual又较为简单。所以决定分析一下,先从几个问题入手:
通过关系图发现我们所有用到的组件都继承自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)中利用这些参数都干了些啥。
在PullToRefreshBase.createLoadingLayout()方法会根据传递的参数(flip or rotate)来创建相应的LoadingLayout,LoadingLayout其有两个子类:RotateLoadingLayout 和 FlipLoadingLayout 分别代表了两种下拉时候所执行的动画所在,这个时候基本上有谱了。
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;
}
}