• RecyclerView 下拉刷新上拉加载


    步骤:

    1. 首先直接定义一个XRecyclerView继承RecyclerView,重写他的三个构造方法。
    2. init(Context mContext)方法用来初始化底部加载的view
    3. 回到XRecyclerView,实现init
    4. 判断是否滑动到底部,并且进行加载
    5. 自定义一个adapter来把底部布局加进去。
    6. 重写Adapter,通过状态判断是否显示“正在加载”
    7. 定义一个mDataObserver

        1. 首先直接定义一个XRecyclerView继承RecyclerView,重写他的三个构造方法。

    public XRecylcerView(Context context) {        
        this(context, null);    
    }    
    public XRecylcerView(Context context, AttributeSet attrs) {
      this(context, attrs, 0); } public XRecylcerView(Context context, AttributeSet attrs, int defStyle){ super(context, attrs, defStyle); init(context); }

        2. init(Context mContext)方法用来初始化底部加载的view

          先自定义一个底部布局LoadingMoreFooter继承Linearlayout,里面是一个居中显示的ProgressBar和一个TextView,添加一个方法setState(int state),来判定当前刷新的状态

    public void setState(int state) {
            switch (state) {
                // 刷新中            
          case STATE_LAODING:                
             progressCon.setVisibility(View.VISIBLE);          mText.setText(
    "正在刷新");          this.setVisibility(View.VISIBLE);   break;       // 刷新完成       case STATE_COMPLETE:          mText.setText("刷新完成");          this.setVisibility(View.GONE);         break;

          // 没有更多数据       case STATE_NOMORE:           mText.setText("没有更多数据啦");
    progressCon.setVisibility(View.GONE);
    this.setVisibility(View.VISIBLE); break;     } }

        3. 回到XRecyclerView,实现init

      private void init(Context context) {
            mContext = context;
            // loadingMoreEnabled为下拉的开关
            if (loadingMoreEnabled) {
                LoadingMoreFooter footerView = new LoadingMoreFooter(mContext);
                addFootView(footerView);
                mFootViews.get(0).setVisibility(GONE);
            }
        }

          RecyclerView的上拉加载,原理很简单,无非就是当滑动到底部的时候,如果有数据,并且允许加载,就请求数据添加到adapter,而RecyclerView需要做的就是当加载的时候,在底部显示正在加载来提醒用户。  

        4.判断是否滑动到底部,并且进行加载

     1 /**
     2      * 监听滑动,来定位当前滑动到哪个地方
     3      *
     4      * @param state
     5      */
     6     @Override
     7     public void onScrollStateChanged(int state) {
     8         super.onScrollStateChanged(state);
     9         if (state == RecyclerView.SCROLL_STATE_IDLE
    10                 && mLoadingListener != null && !isLoadingData && loadingMoreEnabled) {
    11             LayoutManager layoutManager = getLayoutManager();
    12             int lastVisibleItemPosition;
    13             if (layoutManager instanceof GridLayoutManager) {
    14                 lastVisibleItemPosition =
    15                         ((GridLayoutManager) layoutManager).findLastVisibleItemPosition();
    16             } else if (layoutManager instanceof StaggeredGridLayoutManager) {
    17                 int[] into =
    18                         new int[((StaggeredGridLayoutManager) layoutManager).getSpanCount()];
    19                 ((StaggeredGridLayoutManager) layoutManager).findLastVisibleItemPositions(into);
    20                 lastVisibleItemPosition = findMax(into);
    21             } else {
    22                 lastVisibleItemPosition =
    23                         ((LinearLayoutManager) layoutManager).findLastVisibleItemPosition();
    24             }
    25             if (layoutManager.getChildCount() > 0
    26                     && lastVisibleItemPosition >= layoutManager.getItemCount() - 1
    27                     && layoutManager.getItemCount() > layoutManager.getChildCount()
    28                     && !isnomore) {
    29                 View footView = mFootViews.get(0);
    30                 isLoadingData = true;
    31                 if (footView instanceof LoadingMoreFooter) {
    32                     ((LoadingMoreFooter) footView).setState(
    33                             LoadingMoreFooter.STATE_LAODING);
    34                 } else {
    35                     footView.setVisibility(View.VISIBLE);
    36                 }
    37                 mLoadingListener.onLoadMore();
    38                 // 一个回调接口,用来加载数据    
    39             }
    40         }
    41     }

          写到这个地方,基本的上拉加载的逻辑就搞定了,然后就是处理细节。我们需要把底部布局LoadingMoreFooter加载到RecyclerView,这时候重写setAdapter(Adapter adapter)方法来添加一个adapter。

        5. 自定义一个adapter来把底部布局加进去。自定义的Adapter如下:

      1   private class WrapAdapter extends RecyclerView.Adapter<ViewHolder> {
      2     private RecyclerView.Adapter adapter;
      3     private ArrayList<View> mFootViews;
      4     private int headerPosition = 0;
      5 
      6     public WrapAdapter(ArrayList<View> footViews, RecyclerView.Adapter adapter) {
      7         this.adapter = adapter;
      8         this.mFootViews = footViews;
      9     }
     10 
     11     @Override
     12     public void onAttachedToRecyclerView(RecyclerView recyclerView) {
     13         super.onAttachedToRecyclerView(recyclerView);
     14         RecyclerView.LayoutManager manager = recyclerView.getLayoutManager();
     15         if (manager instanceof GridLayoutManager) {
     16             final GridLayoutManager gridManager = ((GridLayoutManager) manager);
     17             gridManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
     18                 @Override
     19                 public int getSpanSize(int position) {
     20                     return (isFooter(position)) ? gridManager.getSpanCount() : 1;
     21                 }
     22             });
     23         }
     24     }
     25 
     26     @Override
     27     public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) {
     28         super.onViewAttachedToWindow(holder);
     29         ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams();
     30         if (lp != null && lp instanceof StaggeredGridLayoutManager.LayoutParams && (isFooter(holder.getLayoutPosition()))
     31         {
     32             StaggeredGridLayoutManager.LayoutParams p = (StaggeredGridLayoutManager.LayoutParams) lp;
     33             p.setFullSpan(true);
     34         }
     35     }
     36 
     37     public boolean isFooter(int position) {
     38         return position < getItemCount() && position >= getItemCount() - mFootViews.size();
     39     }
     40 
     41     public int getFootersCount() {
     42         return mFootViews.size();
     43     }
     44 
     45     @Override
     46     public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
     47         if (viewType == TYPE_FOOTER) {
     48             return new SimpleViewHolder(mFootViews.get(0));
     49         }
     50         return adapter.onCreateViewHolder(parent, viewType);
     51     }
     52 
     53     @Override
     54     public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
     55         if (isHeader(position)) {
     56             return;
     57         }
     58         int adjPosition = position;
     59         int adapterCount;
     60         if (adapter != null) {
     61             adapterCount = adapter.getItemCount();
     62             if (adjPosition < adapterCount) {
     63                 adapter.onBindViewHolder(holder, adjPosition);
     64                 return;
     65             }
     66         }
     67     }
     68 
     69     @Override
     70     public int getItemCount() {
     71         if (adapter != null) {
     72             return getFootersCount() + adapter.getItemCount();
     73         } else {
     74             return getFootersCount();
     75         }
     76     }
     77 
     78     @Override
     79     public int getItemViewType(int position) {
     80         if (isFooter(position)) {
     81             return TYPE_FOOTER;
     82         }
     83         int adjPosition = position;
     84         int adapterCount;
     85         if (adapter != null) {
     86             adapterCount = adapter.getItemCount();
     87             if (adjPosition < adapterCount) {
     88                 return adapter.getItemViewType(adjPosition);
     89             }
     90         }
     91         return TYPE_NORMAL;
     92     }
     93 
     94     @Override
     95     public long getItemId(int position) {
     96         if (adapter != null) {
     97             int adjPosition = position - getHeadersCount();
     98             int adapterCount = adapter.getItemCount();
     99             if (adjPosition < adapterCount) {
    100                 return adapter.getItemId(adjPosition);
    101             }
    102         }
    103         return -1;
    104     }
    105 
    106     private class SimpleViewHolder extends RecyclerView.ViewHolder {
    107         public SimpleViewHolder(View itemView) {
    108             super(itemView);
    109         }
    110     }
    111 }

            就是一个继承自RecyclerView.Adapter的adapter,主要用于根据类型加载不同的布局,普通的itemView和“正在加载”的底部提示。 定义一个mDataObserver

         6. 回到setAdapter(Adapter adapter)方法

       /**
         * 重写Adapter,通过状态判断是否显示“正在加载”
         *
         * @param adapter
         */
        @Override
        public void setAdapter(Adapter adapter) {
            this.mAdapter = adapter;
            this.mWrapAdapter = new WrapAdapter(mFootViews, mAdapter);// 定义WrapAdapter        
            super.setAdapter(mWrapAdapter);// 通过父类方法将自定义的Adapter重新设置进去    
            mAdapter.registerAdapterDataObserver(mDataObserver);//请看下面分析   
        }

        查看super.setAdapter()方法,会找到adapter.registerAdapterDataObserver(mObserver)方法,当adapter里面的数据发生改变时会即时监听并且更新。

        那为什么还要把mAdapter再设置一遍呢?其实当我们调用通过我们自定义的RecyclerView来调用setAdapter方法时,只有当WrapAdapter数据改变的时候,才会有更新,而当我们仅仅只更新mAdapter里面的数据的时候,如果不监听,我们看到的itemView并没有改变。

        7.定义一个mDataObserver

    private final RecyclerView.AdapterDataObserver mDataObserver = new RecyclerView.AdapterDataObserver() {
            @Override
            public void onChanged() {
                mWrapAdapter.notifyDataSetChanged();
            }
    
            @Override
            public void onItemRangeInserted(int positionStart, int itemCount) {
                mWrapAdapter.notifyItemRangeInserted(positionStart, itemCount);
            }
    
            @Override
            public void onItemRangeChanged(int positionStart, int itemCount) {
                mWrapAdapter.notifyItemRangeChanged(positionStart, itemCount);
            }
    
            @Override
            public void onItemRangeChanged(int positionStart, int itemCount, Object payload) {
                mWrapAdapter.notifyItemRangeChanged(positionStart, itemCount, payload);
            }
    
            @Override
            public void onItemRangeRemoved(int positionStart, int itemCount) {
                mWrapAdapter.notifyItemRangeRemoved(positionStart, itemCount);
            }
    
            @Override
            public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
                mWrapAdapter.notifyItemMoved(fromPosition, toPosition);
            }
        };

        都是直接调用父类的方法就可以。

      这样一个RecyclerView的上拉加载逻辑就全部搞定了,这是极其简单的封装方法,所以逻辑没有多么的复杂。

      好的,来回顾一下逻辑:重写RecyclerView进行滑动监听,当滑动到底部的时候通过重写setAdapter来将底部视图加载出来,最后对mAdapter进行数据更改的监听。

      上拉刷新的逻辑更简单,因为有谷歌的SwipeRefreshLayout,所以实现起来就简单很多,首先来看布局文件

    <android.support.v4.widget.SwipeRefreshLayout
      android:id="@+id/swipe"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"/>
    <com.baiyyyhjl.pullrecyclerview.recyclerview.XRecylcerView
        android:id="@+id/recyclerview"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
    </android.support.v4.widget.SwipeRefreshLayout>

      直接用SwipeRefreshLayout将我们刚才自定义的RecyclerView包裹起来,然后swipeRefreshLayout.setOnRefreshListener(this)进行监听,实现onRefresh()接口来实现加载的逻辑。

      就这样,一个简单实用的RecyclerView上拉加载,下拉刷新就实现了。没有多余的布局文件,极其简便。

      当我们项目中有多个RecyclerView并且要求上拉加载,下拉刷新的时候,我们可以定义一个抽象类,只通过修改itemView的布局就能实现。

      

  • 相关阅读:
    Python之坐标轴刻度细化、坐标轴设置、标题图例添加
    探索性数据分析
    http://blog.csdn.net/milton2017/article/details/54406482
    libsvm学习日记--1
    推荐系统评测指标—准确率(Precision)、召回率(Recall)、F值(F-Measure)
    python中if __name__ == '__main__': 的解析
    Python类
    TweenMax学习一
    vuejsLearn---通过手脚架快速搭建一个vuejs项目
    vuejsLearn--- -- 怎么查看、修改、追加数据---->data对象
  • 原文地址:https://www.cnblogs.com/jesonjason/p/5724113.html
Copyright © 2020-2023  润新知