近來需求要求下拉刷新動(dòng)畫Android和iOS統(tǒng)一樣式, 效果如下:

下拉刷新gif
使用SmartRefreshLayout這個(gè)框架自定義Header動(dòng)畫. 感覺這個(gè)框架還是很好用的.
-
把
SmartRefreshLayout加入到項(xiàng)目:compile 'com.android.support:appcompat-v7:25.3.1' compile 'com.scwang.smartrefresh:SmartRefreshLayout:1.0.2-alpha-5' -
在自定義的
Application文件里初始化:public class App extends Application { @Override public void onCreate() { super.onCreate(); initRefreshViewLayout(); } private void initRefreshViewLayout() { MyRefreshLayout.init(); } } -
自定義個(gè)繼承自
SmartRefreshLayout的MyRefreshLayout文件:public class MyRefreshLayout extends SmartRefreshLayout { public static void init() { // 指定全局的下拉Header SmartRefreshLayout.setDefaultRefreshHeaderCreater(new DefaultRefreshHeaderCreater() { @Override public RefreshHeader createRefreshHeader(Context context, RefreshLayout layout) { return new MyRefreshHeader(context); } }); // 指定全局的上拉Footer SmartRefreshLayout.setDefaultRefreshFooterCreater(new DefaultRefreshFooterCreater() { @NonNull @Override public RefreshFooter createRefreshFooter(Context context, RefreshLayout layout) { return new ClassicsFooter(context); } }); } public MyRefreshLayout(Context context) { super(context); initView(context); } public MyRefreshLayout(Context context, AttributeSet attrs) { super(context, attrs); initView(context); } public MyRefreshLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initView(context); } private void initView(Context context) { setReboundDuration(300); // 設(shè)置回彈動(dòng)畫時(shí)長 setPrimaryColorsId(R.color.white); // 主題色 setEnableAutoLoadmore(false); // 設(shè)置是否監(jiān)聽列表在滾動(dòng)到底部時(shí)觸發(fā)加載事件 } // 下拉/上拉完成 public void complete() { if (mState == RefreshState.Loading) { finishLoadmore(); } else { finishRefresh(); } } } -
創(chuàng)建個(gè)
MyRefreshHeader文件, 在這里做自定義的動(dòng)畫:public class MyRefreshHeader extends RelativeLayout implements RefreshHeader { private CircleProgressView mCircleProgressView; private TextView mTextView; private ImageView mArrow; private boolean isArrowDown = false; public MyRefreshHeader(Context context) { super(context); this.initView(context, null, 0); } public MyRefreshHeader(Context context, AttributeSet attrs) { super(context, attrs); this.initView(context, attrs, 0); } public MyRefreshHeader(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); this.initView(context, attrs, defStyleAttr); } private void initView(Context context, AttributeSet attrs, int defStyleAttr) { setMinimumHeight(dp2px(context, 80)); LayoutParams params = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); params.addRule(CENTER_IN_PARENT); View headerView = View.inflate(context, R.layout.my_refresh_header, null); mCircleProgressView = (CircleProgressView) headerView.findViewById(R.id.circleProgressView); mTextView = (TextView) headerView.findViewById(R.id.textview); mArrow = (ImageView) headerView.findViewById(R.id.iv_refresh_center); addView(headerView, params); } @Override public void onInitialized(RefreshKernel kernel, int height, int extendHeight) { // 尺寸定義完成 } @Override public void onPullingDown(float percent, int offset, int headHeight, int extendHeight) { // 手指拖動(dòng)下拉(會(huì)連續(xù)多次調(diào)用) if (mCircleProgressView == null) return; float startPercent = 0.20f; if (percent > startPercent && percent < 1) { float tempPercent = (percent-startPercent) * 1.0f / (1 - startPercent); mCircleProgressView.setProgressPersent(tempPercent); } } @Override public void onReleasing(float percent, int offset, int headHeight, int extendHeight) { // 手指釋放之后的持續(xù)動(dòng)畫 } @Override public void onStartAnimator(RefreshLayout layout, int headHeight, int extendHeight) { RotateAnimation ta = new RotateAnimation(0, 360, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f); ta.setDuration(500); ta.setRepeatCount(10000); ta.setInterpolator(new LinearInterpolator()); ta.setFillAfter(true); mCircleProgressView.startAnimation(ta); } @Override public int onFinish(RefreshLayout layout, boolean success) { mCircleProgressView.clearAnimation(); return 100; // 動(dòng)畫結(jié)束,延遲多少毫秒之后再收回 } @Override public void setPrimaryColors(int... colors) { setBackgroundColor(getResources().getColor(R.color.activity_bg)); } @NonNull public View getView() { return this; } @Override public SpinnerStyle getSpinnerStyle() { return SpinnerStyle.Translate; } @Override public void onStateChanged(RefreshLayout refreshLayout, RefreshState oldState, RefreshState newState) { // 狀態(tài)改變事件 switch (newState) { case None: // 無狀態(tài) if (mCircleProgressView != null) mCircleProgressView.setProgressPersent(0); if (isArrowDown) { arrowAnimation(); isArrowDown = false; } break; case PullDownToRefresh: // 可以下拉狀態(tài) mTextView.setText("下拉即可刷新"); break; case Refreshing: // 刷新中狀態(tài) mTextView.setText("正在刷新數(shù)據(jù)..."); break; case ReleaseToRefresh: // 釋放就開始刷新狀態(tài) mTextView.setText("松開立即刷新"); if (!isArrowDown) { arrowAnimation(); isArrowDown = true; } break; } } private void arrowAnimation() { RotateAnimation ra = new RotateAnimation(0, isArrowDown ? 0 : 180.0f, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f); ra.setDuration(200); ra.setRepeatCount(0); ra.setInterpolator(new LinearInterpolator()); ra.setFillAfter(true); mArrow.startAnimation(ra); } /** * dp轉(zhuǎn)px */ private int dp2px(Context context, float dpVal) { return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpVal, context.getResources().getDisplayMetrics()); } } -
創(chuàng)建一個(gè)貝塞爾畫圓工具
CircleProgressView來畫圓弧:public class CircleProgressView extends View { private RectF mRectF; private Paint mPaint; private int width; private int height; private float persent = 0.0f; // 進(jìn)度 private float lineWidth = 2; // 線寬 public CircleProgressView(Context context) { super(context); lineWidth = dp2px(context, 1.0f); initView(); } public CircleProgressView(Context context, AttributeSet attrs) { super(context, attrs); lineWidth = dp2px(context, 1.0f); initView(); } @Override public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); width = MeasureSpec.getSize(widthMeasureSpec); height = MeasureSpec.getSize(heightMeasureSpec); if (width != height) { int min = Math.min(width, height); width = min; height = min; } mRectF.left = lineWidth / 2; mRectF.top = lineWidth / 2; mRectF.right = width - lineWidth / 2; mRectF.bottom = height - lineWidth / 2; } private void initView() { mRectF = new RectF(); mPaint = new Paint(); mPaint.setAntiAlias(true); mPaint.setColor(getResources().getColor(R.color.theme_color_80)); mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeWidth(lineWidth); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawColor(Color.TRANSPARENT); canvas.drawArc(mRectF, 90, persent * 350, false, mPaint); } public void setProgressPersent(float persent) { this.persent = persent; this.invalidate(); } // dp轉(zhuǎn)px private int dp2px(Context context, float dpVal) { return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpVal, context.getResources().getDisplayMetrics()); } } -
在
res\layout\創(chuàng)建一個(gè)my_refresh_header.xml文件:<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingTop="5dp" > <ImageView android:id="@+id/iv_head" android:layout_width="135dp" android:layout_height="15dp" android:layout_centerHorizontal="true" android:src="@mipmap/refresh_head" /> <RelativeLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_marginTop="12dp" android:layout_below="@+id/iv_head" > <RelativeLayout android:id="@+id/rlCircleContainer" android:layout_width="wrap_content" android:layout_height="wrap_content" > <app.laowen.com.downrefreshdemo.CircleProgressView android:id="@+id/circleProgressView" android:layout_width="22dp" android:layout_height="22dp" android:layout_centerInParent="true" /> <ImageView android:id="@+id/iv_refresh_center" android:layout_width="15dp" android:layout_height="15dp" android:layout_centerInParent="true" android:scaleType="fitCenter" android:src="@mipmap/arrow_up" /> </RelativeLayout> <TextView android:id="@+id/textview" style="@style/text_24_80" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_toRightOf="@+id/rlCircleContainer" android:paddingLeft="10dp" android:text="下拉即可刷新" /> </RelativeLayout> </RelativeLayout> -
使用示例:
public class MainActivity extends AppCompatActivity { private MyRefreshLayout refreshLayout; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); refreshLayout = (MyRefreshLayout)findViewById(R.id.refreshLayout); refreshLayout.setOnRefreshListener(new OnRefreshListener() { @Override public void onRefresh(RefreshLayout refreshlayout) { refreshlayout.finishRefresh(3000); // 模擬請(qǐng)求數(shù)據(jù), 3秒后結(jié)束 } }); refreshLayout.setOnLoadmoreListener(new OnLoadmoreListener() { @Override public void onLoadmore(RefreshLayout refreshlayout) { refreshlayout.finishLoadmore(3000); } }); } }xml:
<?xml version="1.0" encoding="utf-8"?> <app.laowen.com.downrefreshdemo.MyRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/refreshLayout" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/activity_bg" > <android.support.v7.widget.RecyclerView android:id="@+id/recyclerview" android:layout_width="match_parent" android:layout_height="match_parent" android:overScrollMode="never" android:background="#236678" /> </app.laowen.com.downrefreshdemo.MyRefreshLayout>