• Android下拉刷新效果实现


    本文主要包括以下内容

    1. 自定义实现pulltorefreshView
    2. 使用google官方SwipeRefreshLayout

    下拉刷新大致原理

    判断当前是否在最上面而且是向下滑的,如果是的话,则加载数据,并更新界面。

    自定义实现pulltorefreshView

    package com.jimstin.pulltorefreshviewdemo.view;
    
    import com.jimstin.pulltorefreshviewdemo.R;
    
    import android.content.Context;
    import android.content.SharedPreferences;
    import android.graphics.Canvas;
    import android.os.AsyncTask;
    import android.util.AttributeSet;
    import android.view.LayoutInflater;
    import android.view.MotionEvent;
    import android.view.View;
    import android.view.ViewTreeObserver;
    import android.view.ViewTreeObserver.OnPreDrawListener;
    import android.widget.ImageView;
    import android.widget.LinearLayout;
    import android.widget.RelativeLayout;
    import android.widget.ScrollView;
    import android.widget.TextView;
    import android.view.View.OnTouchListener;
    import android.view.animation.Animation;
    import android.view.animation.Animation.AnimationListener;
    import android.view.animation.LinearInterpolator;
    import android.view.animation.RotateAnimation;
    
    public class PullToRefreshView  extends LinearLayout implements OnTouchListener {
    
        private static PullToRefreshView mPullToRefreshView;
        private static Context mContext;
        private AttributeSet mAttrs;
        private View[] childs;
        private RelativeLayout mTopView, mBottomView;
        private MyScrollView mScrollView;
        private LinearLayout mContentView;
        private LayoutParams mParams;
        private static TextView mTopTips, mBottomTips;
        private static ImageView mTopTipsIcon, mBottomTipsIcon;
        private RotateAnimation  toAnmt, backAnmt, progressBarAnmt;
    
        private boolean isToTop, isToBottom;
        private boolean isGetChilds;
        private boolean isRecordY;
        private boolean isContentNotFull;
        private boolean isResetLayoutParams;
        private boolean isActviteScrollEvent;//偏移量达到刷新或加载更多的要求时,为true,否则为false
        private boolean isTurnUp;//判断手势,向上时为true,向下为false
        private static boolean isRefresing;//是否正在刷新
        private static boolean isRefreshed = true;//是否已刷新完毕
        private static boolean isLoading;//是否正在加载
        private static boolean isLoaded = true;//是否已加载完毕
        private static boolean isPulling;//是否正在拖动scrollview
        private boolean isRotate;//是否已经动画
    
        private static int topViewHeight;//topview的高度,和bottomview高度一致
        private int mHeight;//整个PullToRefreshView的高度
        private int scrollToEnd;//scrollview滚动到底部的长度
        private float lastY;//
        private float guestureLastY;//用于记录手势按下屏幕时的第一个位置
    
        private OnRefreshListener mRefreshListener;
        private OnLoadListener mLoadListener;
    
        public PullToRefreshView(Context context, AttributeSet attrs) {
            super(context, attrs);
            mContext = context;
            this.mAttrs = attrs;
            initView();
        }
    
        private void initView() {
            mPullToRefreshView = this;
            toAnmt = new RotateAnimation(0, 180f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
            toAnmt.setDuration(300);
            toAnmt.setFillAfter(true);
            backAnmt = new RotateAnimation(0, -180f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
            backAnmt.setDuration(300);
            backAnmt.setFillAfter(true);
            progressBarAnmt = new RotateAnimation(0, 360f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
            progressBarAnmt.setDuration(1800);
            progressBarAnmt.setRepeatCount(-1);
            progressBarAnmt.setRepeatMode(RotateAnimation.RESTART);
            progressBarAnmt.setInterpolator(new LinearInterpolator());
            toAnmt.setAnimationListener(new AnimationListener() {
    
                @Override
                public void onAnimationStart(Animation animation) {
                    // TODO Auto-generated method stub
    
                }
    
                @Override
                public void onAnimationRepeat(Animation animation) {
                    // TODO Auto-generated method stub
    
                }
    
                @Override
                public void onAnimationEnd(Animation animation) {
                    // TODO Auto-generated method stub
                    mTopTipsIcon.clearAnimation();
                    mTopTipsIcon.setBackgroundResource(R.drawable.ic_up);
                    mBottomTipsIcon.clearAnimation();
                    mBottomTipsIcon.setBackgroundResource(R.drawable.ic_up);
                }
    
            });
    
            backAnmt.setAnimationListener(new AnimationListener() {
    
                @Override
                public void onAnimationStart(Animation animation) {
                    // TODO Auto-generated method stub
    
                }
    
                @Override
                public void onAnimationRepeat(Animation animation) {
                    // TODO Auto-generated method stub
    
                }
    
                @Override
                public void onAnimationEnd(Animation animation) {
                    // TODO Auto-generated method stub
                    mTopTipsIcon.clearAnimation();
                    mTopTipsIcon.setBackgroundResource(R.drawable.ic_down);
                    mBottomTipsIcon.clearAnimation();
                    mBottomTipsIcon.setBackgroundResource(R.drawable.ic_down);
                }
            });
    
            ViewTreeObserver ob = getViewTreeObserver();
            ob.addOnPreDrawListener(new OnPreDrawListener() {
    
                @Override
                public boolean onPreDraw() {
                    if(topViewHeight == 0 || mHeight == 0) {
                        if(topViewHeight == 0) {
                            topViewHeight = mTopView.getHeight();
                        }
                        if(mHeight == 0) {
                            mHeight = getHeight();
                        }
                        if(mHeight > 0 && topViewHeight > 0) {
                            SharedPreferences p = mContext.getSharedPreferences("PullToRefreshView", 0);
                            p.edit().putInt("barHeight", topViewHeight).putInt("height", mHeight).commit();
                        }
                        mParams = new LayoutParams(LayoutParams.MATCH_PARENT, mHeight+2*topViewHeight);
                        setLayoutParams(mParams);
                        setY(-topViewHeight);
                    }
                    return true;
                }
            });
        }
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            // TODO Auto-generated method stub
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        }
    
        @Override
        protected void onFinishInflate() {
            // TODO Auto-generated method stub
            super.onFinishInflate();
            setLayout();
        }
    
        @Override
        protected void onLayout(boolean changed, int l, int t, int r, int b) {
            super.onLayout(changed, l, t, r, b);
        }
    
        public void setLayout() {
            if(!isGetChilds) {
    
                int count = getChildCount();
                childs = new View[count];
                for(int i=0; i<count; i++) {
                    childs[i] = getChildAt(i);
                }
                for(int i=0; i<count; i++) {
                    removeAllViews();
                }
                LayoutInflater inflater = LayoutInflater.from(mContext);
                mTopView = (RelativeLayout) inflater.inflate(R.layout.layout_top_pull_to_refresh_view, null);
                mBottomView = (RelativeLayout) inflater.inflate(R.layout.layout_bottom_pull_to_refresh_view, null);
                mTopTips = (TextView) mTopView.findViewById(R.id.top_tips);
                mBottomTips = (TextView) mBottomView.findViewById(R.id.bottom_tips);
                mTopTipsIcon = (ImageView) mTopView.findViewById(R.id.ic_down);
                mBottomTipsIcon = (ImageView) mBottomView.findViewById(R.id.ic_up);
    
                mScrollView = new MyScrollView(mContext, mAttrs);
                mParams = new LayoutParams(LayoutParams.MATCH_PARENT, 0);
                mParams.weight = 1;
                mScrollView.setLayoutParams(mParams);
                mContentView = new LinearLayout(mContext, mAttrs);
                mContentView.setLayoutParams(mParams);
                mContentView.setOrientation(LinearLayout.VERTICAL);
                for(int i=0; i<count; i++) {
                    mContentView.addView(childs[i]);
                }
                mScrollView.addView(mContentView);
                mScrollView.setOnTouchListener(this);
                addView(mTopView);
                addView(mScrollView);
                addView(mBottomView);
                isGetChilds = true;
            }
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            if(mScrollView.getHeight() > mContentView.getHeight()) {
                isContentNotFull = true;
                mBottomView.setVisibility(View.GONE);
            } else {
                isContentNotFull = false;
            }
        }
        /**
         * 设置刷新监听器
         */
        public void setOnRefreshListener(OnRefreshListener listener) {
            mRefreshListener = listener;
        }
        /**
         * 设置加载监听器
         */
        public void setOnLoadListener(OnLoadListener listener) {
            mLoadListener = listener;
        }
    
        class MyScrollView extends ScrollView {
    
            public MyScrollView(Context context, AttributeSet attrs) {
                super(context, attrs);
            }
    
            @Override
            protected void onScrollChanged(int l, int t, int oldl, int oldt) {
                super.onScrollChanged(l, t, oldl, oldt);
                //MyLog.i("t="+t);
                if(t == 0) {
                    isToTop = true;
                } else {
                    if(t == getChildAt(0).getHeight()-getHeight()) {
                        scrollToEnd = t;
                        isToBottom = true;
                    }
                }
            }
        }
    
        /**
         * 刷新监听器
         */
        public static abstract class OnRefreshListener {
            /**
             * 正在刷新
             */
            public void onRefresh() {
            }
            /**
             * 停止刷新,刷新完毕时请主动调用
             */
            public void stopRefresh() {
                isRefresing = false;
                mTopTips.setText(mContext.getResources().getString(R.string.refreshed));
                mTopTipsIcon.clearAnimation();
                mTopTipsIcon.setBackgroundResource(R.drawable.ic_finish);
                resetYOffset();
            }
        }
        /**
         * 加载更多监听器
         *
         */
        public static abstract class OnLoadListener {
            /**
             * 正在加载
             */
            public void onLoad() {
            }
            /**
             * 停止加载,加载完毕时请主动调用
             */
            public void stopLoad() {
                isLoading = false;
                mBottomTips.setText(mContext.getResources().getString(R.string.loaded));
                mBottomTipsIcon.clearAnimation();
                mBottomTipsIcon.setBackgroundResource(R.drawable.ic_finish);
                resetYOffset();
            }
        }
    
        public static void resetYOffset() {
            new AsyncTask<Integer, Integer, Integer>() {
    
                @Override
                protected Integer doInBackground(Integer... params) {
                    try {
                        Thread.sleep(1000);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    return null;
                }
    
                protected void onPostExecute(Integer result) {
                    if(!isPulling) {
                        mPullToRefreshView.setY(-topViewHeight);
                        mTopTipsIcon.setBackgroundResource(R.drawable.ic_down);
                        mBottomTipsIcon.setBackgroundResource(R.drawable.ic_up);
                        isRefreshed = true;
                        isLoaded = true;
                    }
    
                };
            }.execute();
        }
    
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                guestureLastY = event.getRawY();
                isPulling = true;
                break;
            case MotionEvent.ACTION_MOVE:
    
                if(event.getRawY() - guestureLastY > 0) {
                    isTurnUp = false;
                } else {
                    isTurnUp = true;
                }
                if(isContentNotFull && !isResetLayoutParams) {
                    mParams = new LayoutParams(LayoutParams.MATCH_PARENT, getHeight()-topViewHeight);
                    setLayoutParams(mParams);
                    isResetLayoutParams = true;
                }
                if(isToTop && !isTurnUp) {
    
                    if(!isRecordY) {
                        lastY = event.getRawY()/3;
                        isRecordY = true;
                    }
    
                    mScrollView.setVerticalScrollBarEnabled(false);
                    float y = 0.0f;
                    if(!isRefreshed) {
                        if(!isPulling) {
                            y = event.getRawY()/3 - lastY - topViewHeight;
                        } else {
                            y = event.getRawY()/3 - lastY;
                        }
                    } else {
                        y = event.getRawY()/3 - lastY - topViewHeight;
                    }
                    if(!isRefresing && isRefreshed) {
                        if(Math.abs(event.getRawY()/3 - lastY) >= topViewHeight) {
                            isActviteScrollEvent = true;
                            mTopTips.setText(mContext.getResources().getString(R.string.release_to_refresh));
                            if(!isRotate) {
                                mTopTipsIcon.startAnimation(toAnmt);
                                isRotate = true;
                            }
    
                        } else {
    
                            isActviteScrollEvent = false;
                            mTopTips.setText(mContext.getResources().getString(R.string.pull_to_refresh));
                            if(isRotate) {
                                mTopTipsIcon.startAnimation(backAnmt);
                                isRotate = false;
                            }
                        }
                    }
                    setY(y);
                    if(event.getRawY()/3 - lastY < 0) {
                        isToTop = false;
                        isRecordY = false;
                    } else {
                        mScrollView.setScrollY(0);
                    }
                } else if(isToBottom || isContentNotFull) {
    
                    if(!isRecordY) {
                        lastY = event.getRawY()/3;
                        isRecordY = true;
                    }
    
                    mScrollView.setVerticalScrollBarEnabled(false);
    
                    if(!isLoading && isLoaded) {
                        if(Math.abs(event.getRawY()/3 - lastY) >= topViewHeight) {
                            isActviteScrollEvent = true;
                            mBottomTips.setText(mContext.getResources().getString(R.string.release_to_load));
                            if(!isRotate) {
                                mBottomTipsIcon.startAnimation(backAnmt);
                                isRotate = true;
                            }
                        } else {
                            isActviteScrollEvent = false;
                            mBottomTips.setText(mContext.getResources().getString(R.string.push_to_load));
                            if(isRotate) {
                                mBottomTipsIcon.startAnimation(toAnmt);
                                isRotate = false;
                            }
                        }
                    }
                    float y = 0.0f;
                    if(!isLoaded) {
                        if(isPulling) {
                            y = event.getRawY()/3 - lastY - 2*topViewHeight;
                        } else {
                            y = event.getRawY()/3 - lastY - topViewHeight;
                        }
                    } else {
                        y = event.getRawY()/3 - lastY - topViewHeight;
                    }
                    setY(y);
                    if(event.getRawY()/3 - lastY > 0) {
                        isToBottom = false;
                        isRecordY = false;
                    } else {
                        mScrollView.setScrollY(scrollToEnd);
                    }
                }
                break;
            case MotionEvent.ACTION_UP:
    
                mScrollView.setVerticalScrollBarEnabled(true);
                isRotate = false;
                isRecordY = false;
                isPulling = false;
                if(isActviteScrollEvent) {
                    if(isToTop && !isTurnUp) {
                        if(mRefreshListener != null) {
                            isRefresing = true;
                            isRefreshed = false;
                            setY(0);
                            mTopTips.setText(mContext.getResources().getString(R.string.refreshing));
                            mTopTipsIcon.setBackgroundResource(R.drawable.ic_refresh_progress_bar);
                            mTopTipsIcon.startAnimation(progressBarAnmt);
                            mRefreshListener.onRefresh();
                        }
                    } else if(isToBottom) {
                        if(mLoadListener != null) {
                            setY(-2*topViewHeight);
                            mBottomTips.setText(mContext.getResources().getString(R.string.loading));
                            mBottomTipsIcon.setBackgroundResource(R.drawable.ic_refresh_progress_bar);
                            mBottomTipsIcon.startAnimation(progressBarAnmt);
                            isLoading = true;
                            isLoaded = false;
                            mLoadListener.onLoad();
                        }
                    } else if(isContentNotFull) {
                        setY(-topViewHeight);
                    }
    
                    isActviteScrollEvent = false;
                } else {
                    if(isRefresing) {
                        setY(0);
                    } else if(isLoading) {
                        setY(-2*topViewHeight);
                    } else {
                        setY(-topViewHeight);
    
                    }
                }
                if(!isRefresing) {
                    isRefreshed = true;
                } 
                if(!isLoading) {
                    isLoaded = true;
                }
    
                isToTop = false;
                isToBottom = false;
                break;
    
            default:
                break;
    
                }
                return false;
        }
    
        public void initLayoutParams() {
            SharedPreferences p = mContext.getSharedPreferences("PullToRefreshView", 0);
            topViewHeight = p.getInt("barHeight", 0);
            mHeight = p.getInt("height", 0);
    
            if(mHeight > 0) {
                mParams = new LayoutParams(LayoutParams.MATCH_PARENT, mHeight+2*topViewHeight);
                setLayoutParams(mParams);
                setY(-topViewHeight);
            }
        }
    }

    参考链接

    PullToRefreshView下拉刷新上来加载更多,支持任何子view! - zhangjm_123的专栏 - 博客频道 - CSDN.NET

    SwipeRefreshLayout 使用

    布局文件

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:padding="8dp"
        android:background="#Ffffff"
        >
        <android.support.v4.widget.SwipeRefreshLayout
            android:id="@+id/swipe_refresh_layout_caselist"
            android:layout_marginTop="4dp"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content">
    
        <ListView
            android:id="@+id/list"
            android:scrollbars="none"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:dividerHeight="0dp"
            android:divider="#Ffffff">
    
        </ListView>
        </android.support.v4.widget.SwipeRefreshLayout>
    </LinearLayout>

    在Activity中使用

     @Override
        protected void setUpView() {
            if (mIsFirstCreated)
            {
                onRefresh();
            }
    
            listView = $(R.id.list);
            swipeRefreshLayout=$(R.id.swipe_refresh_layout_caselist);
            //设置刷新时动画的颜色,可以设置4个
            swipeRefreshLayout.setColorSchemeResources(android.R.color.holo_blue_light, android.R.color.holo_red_light, android.R.color.holo_orange_light, android.R.color.holo_green_light);
    
    
            swipeRefreshLayout.setOnRefreshListener(this);
            getData();
    //        BaseAdapter arrayAdapter = new ArrayAdapter(getActivity(),R.layout.item_list,R.id.name,
    //                Arrays.asList("美食劵", "活动劵", "优惠劵", "团购劵", "外卖劵"));
    //        listView.setAdapter(arrayAdapter);
    
        }
    
    
    
    
    
        @Override
        public void onRefresh() {
            //tv.setText("正在刷新");
            // TODO Auto-generated method stub
            mIsFirstCreated = false;
            getData();
    
        }

    使用的类要实现SwipeRefreshLayout.OnRefreshListener接口

    并且在数据获取成功后发送消息,设置swipeRefreshLayout.setRefreshing(false);

    参考链接

    Google自己的下拉刷新组件SwipeRefreshLayout - 李金尧 - 博客园

    你还在用开源控件的下拉刷新吗?你out了,试一试官方的下拉刷新SwipeRefreshLayout - 推酷

  • 相关阅读:
    hdu1089
    hdu1088
    驴妈妈
    途牛悄然上市 登陆SEC途牛前景如何
    途牛旅游网
    百度-----携程
    携程旅行网
    手机游戏
    web
    改造 改革
  • 原文地址:https://www.cnblogs.com/jjx2013/p/6223628.html
Copyright © 2020-2023  润新知