一個(gè)Android下拉刷新樣式

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

下拉刷新gif

使用SmartRefreshLayout這個(gè)框架自定義Header動(dòng)畫. 感覺這個(gè)框架還是很好用的.

  1. SmartRefreshLayout加入到項(xiàng)目:

    compile 'com.android.support:appcompat-v7:25.3.1'
    compile 'com.scwang.smartrefresh:SmartRefreshLayout:1.0.2-alpha-5'
    
  2. 在自定義的Application文件里初始化:

    public class App extends Application {
        @Override
        public void onCreate() {
            super.onCreate();
            initRefreshViewLayout();
        }
    
        private void initRefreshViewLayout() {
            MyRefreshLayout.init();
        }
    }
    
  3. 自定義個(gè)繼承自SmartRefreshLayoutMyRefreshLayout文件:

    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();
            }
        }
    }
    
  4. 創(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());
        }
    }   
    
  5. 創(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());
        }
    }
    
  6. 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>
    
  7. 使用示例:

    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>
    
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容