• listview下拉刷新和上拉加载更多的多种实现方案


         listview经常结合下来刷新和上拉加载更多使用,本文总结了三种常用到的方案分别作出说明。

         方案一:添加头布局和脚布局
            android系统为listview提供了addfootview和addheadview两个API。这样可以直接自定义一个View,以添加视图的形式实现下来刷新和上拉加载。
         实现步骤
           1、创建一个类继承ListView:class PullToRefreshListView extends ListView;
           2、在构造方法中添加HeadView:addHeaderView(headView);
           3、获取HeadView的高。测量控件的高可以有两方法getMeasuredHeight和getHeight,getMeasuredHeight()在onMeasure方法执行之后才能获取到;getHeight()  在onLayout方法执行之后才能获取到值;
           4、显示和隐藏headView,通过setpadding实现,当向下滑,且第一条可见item是第0条的时候才需要设置HeadView的paddingTop来显示HeadView。
                  显示:headView.setPadding(0,0,0,0);
                  隐藏:headView.setPadding(0,-headViewHeight,0,0);
           5、下拉刷新三种状态的判断,移动的时候,当paddingTop < 0 的时候,说明HeadView没有完全显示出来,进入下拉刷新状态;移动的时候,当paddingTop >= 0 的时候,   说明HeadView已经完全显示出来了,进入松开以新状态;手指抬起的时候,且当前状态是松开刷新状态的时候,进入正在刷新状态; 当已经是“正在刷新”状态时,   则不允许再做”下拉刷新”和”松开刷新”的操作了,在Move事件中加入判断,如果已经是正在刷新状态了,则不处理下拉的操作了。
           6、下拉箭头的转动。下拉刷新是向下,松开刷新时向上。旋转动画通过属性动画实现。隐藏箭头的时候要清除动画:iv_arrow.clearAnimation();  如果不隐藏动画效果,设置View.GONE之后还是看得见的。
           7、HeadView显示时,当手指松开时的处理,松开时如果是“正在刷新”状态,则把headVie完全显示;松开时如果是“下拉刷新”状态,则把HeadView完全隐藏。
           8、增加FooterView:addFooterView(footerView)。当ListView处于空闲状态,并且最后一条可见item是ListView中的最后一条数据时显示footview,   footerView显示出来后,ListView不会自动上滑把FooterView显示出来的,所以需要手动设置:setSelection(getCount() - 1);即选中最后一条。
           9、增加回调监听器。当ListView处于刷新状态的时候会调用onRefreshing()方法;当ListView处于加载更多的时候会调用onLoadMore()。加载完成后通知控件加载完成。

           具体实现:

    import com.itheima.pulltorefreshlistview.R;
    
    import android.content.Context;
    import android.util.AttributeSet;
    import android.view.MotionEvent;
    import android.view.View;
    import android.view.animation.RotateAnimation;
    import android.widget.AbsListView;
    import android.widget.ImageView;
    import android.widget.ListView;
    import android.widget.ProgressBar;
    import android.widget.TextView;
    
    public class PullToRefreshListView extends ListView {
    
        private View headerView;
        private float downY;
        private int headerViewHeight;
        /** 状态:下拉刷新 */
        private static final int STATE_PULL_TO_REFRESH = 0;
        /** 状态:松开刷新 */
        private static final int STATE_RELEASE_REFRESH = 1;
        /** 状态:正在刷新 */
        private static final int STATE_REFRESHING = 2;
        /** 当前状态 */
        private int currentState = STATE_PULL_TO_REFRESH;    // 默认是下拉刷新状态
        private ImageView iv_arrow;
        private ProgressBar progress_bar;
        private TextView tv_state;
        private RotateAnimation upAnim;
        private RotateAnimation downAnim;
        private OnRefreshingListener mOnRefreshingListener;
        private View footerView;
        private int footerViewHeight;
        /** 正在加载更多 */
        private boolean loadingMore;
    
        public PullToRefreshListView(Context context, AttributeSet attrs) {
            super(context, attrs);
            initHeaderView();
            initFooterView();
        }
        
        private void initHeaderView() {
            headerView = View.inflate(getContext(), R.layout.header_view, null);
            iv_arrow = (ImageView) headerView.findViewById(R.id.iv_arrow);
            progress_bar = (ProgressBar) headerView.findViewById(R.id.progress_bar);
            showRefreshingProgressBar(false);
            tv_state = (TextView) headerView.findViewById(R.id.tv_state);
            headerView.measure(0, 0);    // 主动触发测量,mesure内部会调用onMeasure
            headerViewHeight = headerView.getMeasuredHeight();
            hideHeaderView();
            super.addHeaderView(headerView);
            upAnim = createRotateAnim(0f, -180f);
            downAnim = createRotateAnim(-180f, -360f);
        }
        
        private void initFooterView() {
            footerView = View.inflate(getContext(), R.layout.footer_view, null);
            footerView.measure(0, 0);// 主动触发测量,mesure内部会调用onMeasure
            footerViewHeight = footerView.getMeasuredHeight();
            hideFooterView();
            super.addFooterView(footerView);
            
            super.setOnScrollListener(new OnScrollListener() {
                
                // 当ListView滚动的状态发生改变的时候会调用这个方法
                @Override
                public void onScrollStateChanged(AbsListView view, int scrollState) {
                    if (scrollState == OnScrollListener.SCROLL_STATE_IDLE    // ListView处于空闲状态
                            && getLastVisiblePosition() == getCount() - 1    // 界面上可见的最后一条item是ListView中最后的一条item
                            && loadingMore == false                            // 如果当前没有去做正在加载更多的事情
                            ) {
                        loadingMore = true;
                        showFooterView();
                        setSelection(getCount() - 1);
                        
                        if (mOnRefreshingListener != null) {
                            mOnRefreshingListener.onLoadMore();
                        }
                    }
                }
                
                // 当ListView滚动的时候会调用这个方法
                @Override
                public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
                    
                }
            });
        }
    
        private void hideFooterView() {
            int paddingTop = -footerViewHeight;
            setFooterViewPaddingTop(paddingTop);
        }
        
        private void showFooterView() {
            int paddingTop = 0;
            setFooterViewPaddingTop(paddingTop);
        }
    
        private void setFooterViewPaddingTop(int paddingTop) {
            footerView.setPadding(0, paddingTop, 0, 0);
        }
    
        /**
         * 设置显示进度的圈圈
         * @param showProgressBar 如果是true,则显示ProgressBar,否则的话显示箭头
         */
        private void showRefreshingProgressBar(boolean showProgressBar) {
            progress_bar.setVisibility(showProgressBar ? View.VISIBLE : View.GONE);
            iv_arrow.setVisibility(!showProgressBar ? View.VISIBLE : View.GONE);
            
            if (showProgressBar) {
                iv_arrow.clearAnimation();    // 有动画的View要清除动画才能真正的隐藏
            }
        }
    
        /**
         * 创建旋转动画
         * @param fromDegrees 从哪个角度开始转
         * @param toDegrees 转到哪个角度
         * @return 
         */
        private RotateAnimation createRotateAnim(float fromDegrees, float toDegrees) {
            int pivotXType = RotateAnimation.RELATIVE_TO_SELF;        // 旋转点的参照物
            int pivotYType = RotateAnimation.RELATIVE_TO_SELF;        // 旋转点的参照物
            float pivotXValue = 0.5f;    // 旋转点x方向的位置
            float pivotYValue = 0.5f;    // 旋转点y方向的位置
            RotateAnimation ra = new RotateAnimation(fromDegrees, toDegrees, pivotXType, pivotXValue, pivotYType, pivotYValue);
            ra.setDuration(300);
            ra.setFillAfter(true);    // 让动画停留在结束位置
            return ra;
        }
    
        /** 隐藏HeaderView */
        private void hideHeaderView() {
            int paddingTop = -headerViewHeight;
            setHeaderViewPaddingTop(paddingTop);
        }
        
        /** 显示HeaderView */
        private void showHeaderView() {
            int paddingTop = 0;
            setHeaderViewPaddingTop(paddingTop);
        }
    
        /**
         * 设置HeaderView的paddingTop
         * @param paddingTop
         */
        private void setHeaderViewPaddingTop(int paddingTop) {
            headerView.setPadding(0, paddingTop, 0, 0);
        }
        
        @Override
        public boolean onTouchEvent(MotionEvent ev) {
            switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                downY = ev.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                if (currentState == STATE_REFRESHING) {
                    // 如果当前已经是“正在刷新“的状态了,则不用去处理下拉刷新了
                    return super.onTouchEvent(ev);
                }
                
                int fingerMoveDistanceY = (int) (ev.getY() - downY);        // 手指移动的距离
                // 如果是向下滑动,并且界面上可见的第一条item是ListView的索引为0的item时我们才处理下拉刷新的操作
                if (fingerMoveDistanceY > 0 && getFirstVisiblePosition() == 0) {
                    int paddingTop = -headerViewHeight + fingerMoveDistanceY;
                    setHeaderViewPaddingTop(paddingTop);
                    
                    if (paddingTop < 0 && currentState != STATE_PULL_TO_REFRESH) {
                        // 如果paddingTop小于0,说明HeaderView没有完全显示出来,则进入下拉刷新的状态
                        currentState = STATE_PULL_TO_REFRESH;
                        tv_state.setText("下拉刷新");
                        iv_arrow.startAnimation(downAnim);
                        showRefreshingProgressBar(false);
                        // 让箭头转一下
                    } else if (paddingTop >= 0 && currentState != STATE_RELEASE_REFRESH) {
                        // 如果paddingTop>=0,说明HeaderView已经完全显示出来,则进入松开刷新的状态
                        currentState = STATE_RELEASE_REFRESH;
                        tv_state.setText("松开刷新");
                        iv_arrow.startAnimation(upAnim);
                        showRefreshingProgressBar(false);
                        
                    }
                    return true;
                }
                break;
            case MotionEvent.ACTION_UP:
                if (currentState == STATE_RELEASE_REFRESH) {
                    // 如果当前状态是松开刷新,并且抬起了手,则进入正在刷新状态
                    currentState = STATE_REFRESHING;
                    tv_state.setText("正在刷新");
                    showRefreshingProgressBar(true);
                    showHeaderView();
                    
                    if (mOnRefreshingListener != null) {
                        mOnRefreshingListener.onRefreshing();
                    }
                } else if (currentState == STATE_PULL_TO_REFRESH) {
                    // 如果抬起手时是下拉刷新状态,则把HeaderView完成隐藏
                    hideHeaderView();
                }
                break;
            }
            return super.onTouchEvent(ev);
        }
    
        public void setOnRefreshingListener(OnRefreshingListener mOnRefreshingListener) {
            this.mOnRefreshingListener = mOnRefreshingListener;
        }
        
        /** ListView刷新的监听器 */
        public interface OnRefreshingListener {
            /** 当ListView可以刷新数据的时候会调用这个方法 */
            void onRefreshing();
            /** 当ListView可以加载更多 的时候会调用这个方法 */
            void onLoadMore();
        }
    
        /** 联网刷新数据的操作已经完成了 */
        public void onRefreshComplete() {
            hideHeaderView();
            currentState = STATE_PULL_TO_REFRESH;
            showRefreshingProgressBar(false);
        }
    
        /** 加载更多新数据的操作已经完成了 */
        public void onLoadmoreComplete() {
            hideFooterView();
            loadingMore = false;
        }
    
    }

         调用listview: 

     listView = (PullToRefreshListView) findViewById(R.id.list_view);
            listView.setAdapter(adapter); 
            listView.setOnRefreshingListener(new OnRefreshingListener() {
             @Override            
             public void onRefreshing() {
               reloadData();
              }
             @Override
             public void onLoadMore() {
              oadMore();             
              }
             });

        方案二: listview的多种样式显示
            设置listview的适配器的时候可以实现两个方法: getViewTypeCount()和getItemViewType(),前者指定条目的种类,后者返回具体的类型,这样可以根据不同的类型设计相关的样式,包括上拉加载更多,和下拉刷新,两者类似,因此这里仅仅给出加载更多的写法。具体实现如下:

            1、重写getViewTypeCount()和getItemViewType(),这里包括普通的item条目和加载更多的条目,所以getViewTypeCount()返回值为2;

    @Override
        public int getViewTypeCount() {
            return super.getViewTypeCount() + 1;
        }
    
        @Override
        public int getItemViewType(int position) {
            if (position == getCount() - 1) {
                return 0;
            } else {
                return addViewType(position); //构造一个方法出来,方便子类修改,添加更多的样式
            }
        }
    
        public int addViewType(int position) {
            return 1;
        }

             2、在getview()中针对不同的类型添加布局:

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            BaseHoldle holdle;
            if (convertView == null) {
                if (getItemViewType(position) == 0) {  //type为0 表示应该加载加载更多的视图
                    holdle = getLoadmoreHoldle();
                } else {                               //否则为普通视图
                    holdle = getSpecialBaseHoldle(position);
                }
            } else {
                holdle = (BaseHoldle) convertView.getTag();
            }
    
            if (getItemViewType(position) == 0) {      //加载更多视图,请求网络获取数据
                if (havemore()) {
                    holdle.setDataAndRefreshHoldleView(LoadmoreHoldle.LOADMORE_LODING);
                    triggleLoadMoreData();
                } else {                              
                    holdle.setDataAndRefreshHoldleView(LoadmoreHoldle.LOADMORE_NONE);
                }
            } else {                                  //普通视图视图,请求网络获取数据
    
                T data = (T) mdata.get(position);
                holdle.setDataAndRefreshHoldleView(data);
            }
    
            mHoldleView = holdle.mHoldleView;
            mHoldleView.setScaleX(0.6f);
            mHoldleView.setScaleY(0.6f);
            ViewCompat.animate(mHoldleView).scaleX(1).scaleY(1).setDuration(400).setInterpolator(new OvershootInterpolator(4)).start();
            return mHoldleView;
        }

               3、具体的加载更多视图的实现

     private BaseHoldle getLoadmoreHoldle() {
            if (mLoadmoreHoldle == null) {
                mLoadmoreHoldle = new LoadmoreHoldle();
            }
            return mLoadmoreHoldle;
        }
    
        public class LoadmoreHoldle extends BaseHoldle {
        @Bind(R.id.item_loadmore_container_loading)
        LinearLayout itemloadmorecontainerloading;
        @Bind(R.id.item_loadmore_container_retry)
        LinearLayout itemloadmorecontainerretry;
        @Bind(R.id.item_loadmore_tv_retry)
        TextView item_loadmore_tv_retry;
    
        public static final int LOADMORE_LODING = 0;
        public static final int LOADMORE_ERROR = 1;
        public static final int LOADMORE_NONE = 2;
        private int mCurretState;
    
        @Override
        public void refreshHoldleView(Object data) {
            itemloadmorecontainerloading.setVisibility(View.GONE);
            itemloadmorecontainerretry.setVisibility(View.GONE);
            mCurretState = (int) data;
            switch (mCurretState) {
                case LOADMORE_LODING:
                    itemloadmorecontainerloading.setVisibility(View.VISIBLE);
                    break;
                case LOADMORE_ERROR:
                    itemloadmorecontainerretry.setVisibility(View.VISIBLE);
                    break;
                case LOADMORE_NONE:
                    break;
            }
        }
    
        @Override
        public View ininViewHoldle() {
            View view = View.inflate(UiUtils.getContext(), R.layout.itemloadmore, null);
            ButterKnife.bind(this, view);
            return view;
        }
    }
    
    //holder基类,提取公共的方法
    public abstract class BaseHoldle<T> {
        public View mHoldleView;
    
        public T mdata;
    
        public BaseHoldle() {
            mHoldleView = ininViewHoldle();
            mHoldleView.setTag(this);
        }
    
        public void setDataAndRefreshHoldleView(T mdata) {
            this.mdata = mdata;
            refreshHoldleView(mdata);
        }
    
        public abstract void refreshHoldleView(T data);
    
        public abstract View ininViewHoldle();
    
    }

    方案三: SwipeRefreshLayout实现下来刷新
         SwipeRefreshLayout对下不兼容,且只有下拉刷新功能没有上拉加载更多的功能。当时作为Andriod5.0之后的新特性,使用起来方便,可以直接调用系统的API。使用方法也较为简单。具体实现如下:
        首先声明控件,设置颜色:  

     refreshLayout = (SwipeRefreshLayout) findViewById(R.id.refresh);
         refreshLayout.setOnRefreshListener(this); 
         refreshLayout.setColorSchemeResources(android.R.color.holo_blue_bright,
                android.R.color.holo_green_light,android.R.color.holo_orange_light,
                android.R.color.holo_red_light);
         refreshLayout.setProgressBackgroundColor(R.color.refresh_bg);
         refreshLayout.setProgressBackgroundColor(R.color.refresh_bg);

        写一个类实现SwipeRefreshLayout.OnRefreshListener,重写onRefresh()方法: 

       @Override   
        public void onRefresh() {  
          refreshLayout.postDelayed(new Runnable() {
           @Override
           public void run() {
             //请求网络,获取数据               
             refreshLayout.setRefreshing(false);
            }
           },3000);
        }


        
      

  • 相关阅读:
    顺序栈--Java实现
    优先队列(存储结构数组)--Java实现
    队列(存储结构数组)--Java实现
    有序链表--Java实现
    双向链表--Java实现
    表达式求值--Java实现
    【Mac + Appium】之运行报错:[UiAutomator] UiAutomator exited unexpectedly with code 0, signal null
    【Mac + ATX基于uiautomator2】使用weditor时,报错:requests.exceptions.ConnectionError: ('Connection aborted.', ConnectionResetError(54, 'Connection reset by peer'))
    【Mac系统 + Python + Django】之开发一个发布会系统【Django模型(三)】
    【转】【Mac系统】之ADB命令总结
  • 原文地址:https://www.cnblogs.com/huangjie123/p/6220134.html
Copyright © 2020-2023  润新知