通过阅读PullToRefresh开源的源码,自我总结下重新实现一个刷新动态图的方法。
11:自定义个HeaderLayout 继承自 LoadingLayout
public class MyLoadingLayout extends LoadingLayout {
static final int FLIP_ANIMATION_DURATION = 150;
private final Animation mRotateAnimation, mResetRotateAnimation;
public MyLoadingLayout(Context context, PullToRefreshBase.Mode mode, PullToRefreshBase.Orientation scrollDirection, TypedArray attrs) {
super(context, mode, scrollDirection, attrs);
final int rotateAngle = mode == PullToRefreshBase.Mode.PULL_FROM_START ? -180 : 180;
<span style="white-space:pre"> </span>mRotateAnimation = new RotateAnimation(0, rotateAngle, Animation.RELATIVE_TO_SELF, 0.5f,
<span style="white-space:pre"> </span>Animation.RELATIVE_TO_SELF, 0.5f);
<span style="white-space:pre"> </span>mRotateAnimation.setInterpolator(ANIMATION_INTERPOLATOR);
<span style="white-space:pre"> </span>mRotateAnimation.setDuration(FLIP_ANIMATION_DURATION);
<span style="white-space:pre"> </span>mRotateAnimation.setFillAfter(true);
<span style="white-space:pre"> </span>mResetRotateAnimation = new RotateAnimation(rotateAngle, 0, Animation.RELATIVE_TO_SELF, 0.5f,
<span style="white-space:pre"> </span>Animation.RELATIVE_TO_SELF, 0.5f);
<span style="white-space:pre"> </span>mResetRotateAnimation.setInterpolator(ANIMATION_INTERPOLATOR);
<span style="white-space:pre"> </span>mResetRotateAnimation.setDuration(FLIP_ANIMATION_DURATION);
<span style="white-space:pre"> </span>mResetRotateAnimation.setFillAfter(true);
}
@Override
protected void onLoadingDrawableSet(Drawable imageDrawable) {
<span style="white-space:pre"> </span>if (null != imageDrawable) {
<span style="white-space:pre"> </span>final int dHeight = imageDrawable.getIntrinsicHeight();
final int dWidth = imageDrawable.getIntrinsicWidth();
<span style="white-space:pre"> </span>/**
* We need to set the width/height of the ImageView so that it is
* square with each side the size of the largest drawable dimension.
* This is so that it doesn't clip when rotated.
*/
<span style="white-space:pre"> </span>ViewGroup.LayoutParams lp = mHeaderImage.getLayoutParams();
<span style="white-space:pre"> </span>lp.width = lp.height = Math.max(dHeight, dWidth);
<span style="white-space:pre"> </span>mHeaderImage.requestLayout();
/**
* We now rotate the Drawable so that is at the correct rotation,
* and is centered.
*/
<span style="white-space:pre"> </span>mHeaderImage.setScaleType(ImageView.ScaleType.MATRIX);
<span style="white-space:pre"> </span>Matrix matrix = new Matrix();
<span style="white-space:pre"> </span>matrix.postTranslate((lp.width - dWidth) / 2f, (lp.height - dHeight) / 2f);
<span style="white-space:pre"> </span>matrix.postRotate(getDrawableRotationAngle(), lp.width / 2f, lp.height / 2f);
<span style="white-space:pre"> </span>mHeaderImage.setImageMatrix(matrix);
<span style="white-space:pre"> </span>}
}
@Override
protected void onPullImpl(float scaleOfLayout) {
// NO-OP
}
@Override
protected void pullToRefreshImpl() {
// Only start reset Animation, we've previously show the rotate anim
if (mRotateAnimation == mHeaderImage.getAnimation()) {
mHeaderImage.startAnimation(mResetRotateAnimation);
}
}
@Override
protected void refreshingImpl() {
mHeaderImage.clearAnimation();
mHeaderImage.setVisibility(View.GONE);
mHeaderProgress.setVisibility(View.GONE);
mHeaderLoadingView.setVisibility(View.VISIBLE);
}
@Override
protected void releaseToRefreshImpl() {
mHeaderImage.startAnimation(mRotateAnimation);
}
@Override
protected void resetImpl() {
mHeaderImage.clearAnimation();
mHeaderProgress.setVisibility(View.GONE);
mHeaderImage.setVisibility(View.VISIBLE);
mHeaderLoadingView.stopAnimation();
mHeaderLoadingView.setVisibility(View.GONE);
}
@Override
protected int getDefaultDrawableResId() {
return R.mipmap.indicator_arrow;
}
private float getDrawableRotationAngle() {
float angle = 0f;
switch (mMode) {
case PULL_FROM_END:
if (mScrollDirection == PullToRefreshBase.Orientation.HORIZONTAL) {
angle = 90f;
} else {
angle = 180f;
}
break;
case PULL_FROM_START:
if (mScrollDirection == PullToRefreshBase.Orientation.HORIZONTAL) {
angle = 270f;
}
break;
default:
break;
}
return angle;
}
}
public class MyAnimationView extends View {
public static final float RADIUS = 20f;
private Paint mPaint;
private Paint outPaint;
private float minRadius = 12f;
private float Router = minRadius;
private float Rinner = minRadius;
private boolean startAnim = true;
private int innerInt = 255;
private int outerInt = 255;
private ValueAnimator anim;
public MyAnimationView(Context context, AttributeSet attrs) {
super(context, attrs);
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
outPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setColor(Color.GRAY);
outPaint.setColor(Color.GRAY);
}
@Override
protected void onDraw(Canvas canvas) {
drawCircle(canvas);
if (startAnim)
startAnimation();
}
private void drawCircle(Canvas canvas) {
mPaint.setAlpha(innerInt);
outPaint.setAlpha(outerInt);
canvas.drawCircle(RADIUS, getHeight()/2, Router, outPaint);
canvas.drawCircle(RADIUS * 3 , getHeight() / 2, Rinner, mPaint);
canvas.drawCircle(RADIUS * 5, getHeight() / 2, Router, outPaint);
}
private void startAnimation() {
anim = ValueAnimator.ofFloat(0,1);
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
innerInt = 144 + (int)(144*(0.5f - (float)animation.getAnimatedValue()));
outerInt = 144 + (int)(144*((float)animation.getAnimatedValue()-0.5f));
Router = minRadius + minRadius* (0.5f - (float)animation.getAnimatedValue());
Rinner = minRadius + minRadius* ((float)animation.getAnimatedValue()-0.5f);
invalidate();
}
});
anim.setDuration(500);
anim.setRepeatCount(Animation.INFINITE);
anim.setRepeatMode(Animation.REVERSE);
anim.start();
startAnim = false;
}
public void stopAnimation(){
if (anim !=null)
anim.cancel();
startAnim = true;
}
}
3.在Headerlayout 布局中添加自己的View
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left|center_vertical" >
<ImageView
android:id="@+id/pull_to_refresh_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center" />
<ProgressBar
android:id="@+id/pull_to_refresh_progress"
style="?android:attr/progressBarStyleSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:indeterminate="true"
android:visibility="gone" />
<com.handmark.pulltorefresh.library.internal.MyAnimationView
android:id="@+id/pull_to_refresh_myview"
android:layout_width="100dp"
android:layout_height="50dp"
android:visibility="gone"/>
</FrameLayout>
4.在PullToRefreshBase中添加自己的模式
public static enum AnimationStyle {
/**
* This is the default for Android-PullToRefresh. Allows you to use any
* drawable, which is automatically rotated and used as a Progress Bar.
*/
ROTATE,
/**
* This is the old default, and what is commonly used on iOS. Uses an
* arrow image which flips depending on where the user has scrolled.
*/
FLIP,
MY;
static AnimationStyle getDefault() {
return MY;
}
/**
* Maps an int to a specific mode. This is needed when saving state, or
* inflating the view from XML where the mode is given through a attr
* int.
*
* @param modeInt - int to map a Mode to
* @return Mode that modeInt maps to, or ROTATE by default.
*/
static AnimationStyle mapIntToValue(int modeInt) {
switch (modeInt) {
case 0x0:
default:
return ROTATE;
case 0x1:
return FLIP;
}
}
LoadingLayout createLoadingLayout(Context context, Mode mode, Orientation scrollDirection, TypedArray attrs) {
switch (this) {
case ROTATE:
default:
return new RotateLoadingLayout(context, mode, scrollDirection, attrs);
case FLIP:
return new FlipLoadingLayout(context, mode, scrollDirection, attrs);
case MY:
return new MyLoadingLayout(context, mode, scrollDirection, attrs);
}
}
}
5.修改各个时段的文字
public final void refreshing() {
if (null != mHeaderText) {
int i = new Random().nextInt(3) + 1;
if ( i == 1)
mRefreshingLabel = mContext.getResources().getString(R.string.pull_to_refresh_refreshing_label);
else if(i==2)
mRefreshingLabel = mContext.getResources().getString(R.string.pull_to_refresh_refreshing_lable_2);
else if (i ==3)
mRefreshingLabel = mContext.getResources().getString(R.string.pull_to_refresh_refreshing_lable_3);
SpannableString s = new SpannableString(mRefreshingLabel);
s.setSpan(new AbsoluteSizeSpan(12,true),4,mRefreshingLabel.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
mHeaderText.setText(s);
}
if (mUseIntrinsicAnimation) {
((AnimationDrawable) mHeaderImage.getDrawable()).start();
} else {
// Now call the callback
refreshingImpl();
}
if (null != mSubHeaderText) {
mSubHeaderText.setVisibility(View.GONE);
}
}