自定义PullToRefresh HeadLayout

本文详细介绍了如何通过阅读PullToRefresh开源源码,实现自定义刷新动态图的方法,包括HeaderLayout的定制、动画View的创建、布局调整及自定义模式的添加,并在各个时段进行了文字的修改。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

通过阅读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;
}
}


2.自定义动画View

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);
}
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值