实现Android RecyclerView上拉加载功能





实现思路


一、XML的实现 


布局很简单,只有一个SwipeRefreshLayout包裹了一个RecyclerView,相信用过RecyclerView的都很容易看懂。如下为activity_main.xml:

[html]  view plain  copy
 print ?
  1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     android:layout_width="match_parent"  
  3.     android:layout_height="match_parent"  
  4.     android:orientation="vertical">  
  5.   
  6.     <android.support.v4.widget.SwipeRefreshLayout  
  7.         android:id="@+id/refreshLayout"  
  8.         android:layout_width="match_parent"  
  9.         android:layout_height="match_parent">  
  10.   
  11.         <android.support.v7.widget.RecyclerView  
  12.             android:id="@+id/recyclerView"  
  13.             android:layout_width="match_parent"  
  14.             android:layout_height="match_parent"/>  
  15.   
  16.     </android.support.v4.widget.SwipeRefreshLayout>  
  17.   
  18. </LinearLayout>  



然后,我们RecyclerView的Item布局也是非常简单,只有一个TextView。如下为item.xml:

[html]  view plain  copy
 print ?
  1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     android:layout_width="match_parent"  
  3.     android:layout_height="wrap_content"  
  4.     android:orientation="vertical">  
  5.   
  6.     <TextView  
  7.         android:id="@+id/tv"  
  8.         android:layout_width="match_parent"  
  9.         android:layout_height="120dp"  
  10.         android:background="@android:color/holo_blue_dark"  
  11.         android:gravity="center"  
  12.         android:textSize="30sp"  
  13.         android:textColor="#ffffff"  
  14.         android:text="11"  
  15.         android:layout_marginBottom="1dp"/>  
  16.   
  17. </LinearLayout>  

看到我们效果图都知道,在我们上拉时,还有一个提示的条目,我定义为 footview.xml:

[html]  view plain  copy
 print ?
  1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     android:layout_width="match_parent"  
  3.     android:layout_height="wrap_content"  
  4.     android:orientation="vertical">  
  5.   
  6.     <TextView  
  7.         android:id="@+id/tips"  
  8.         android:layout_width="match_parent"  
  9.         android:layout_height="wrap_content"  
  10.         android:gravity="center"  
  11.         android:padding="30dp"  
  12.         android:textSize="15sp"  
  13.         android:layout_marginBottom="1dp"/>  
  14.   
  15. </LinearLayout>  


二、初始化SwipeRefreshLayout


在准备好了布局文件之后,我们就把目光转到Activity中去,首先我们需要初始化SwipeRefreshLayout,初始化也是很简单,这里省去了findView操作,所以就只有设置转动的颜色,还有设置刷新的监听事件:

[java]  view plain  copy
 print ?
  1. private void initRefreshLayout() {  
  2.     refreshLayout.setColorSchemeResources(android.R.color.holo_blue_light, android.R.color.holo_red_light,  
  3.             android.R.color.holo_orange_light, android.R.color.holo_green_light);  
  4.     refreshLayout.setOnRefreshListener(this);  
  5. }  
  6.   
  7. @Override  
  8. public void onRefresh() {  
  9.     // 设置可见  
  10.     refreshLayout.setRefreshing(true);  
  11.     // 重置adapter的数据源为空  
  12.     adapter.resetDatas();  
  13.     // 获取第第0条到第PAGE_COUNT(值为10)条的数据  
  14.     updateRecyclerView(0, PAGE_COUNT);  
  15.     mHandler.postDelayed(new Runnable() {  
  16.         @Override  
  17.         public void run() {  
  18.             // 模拟网络加载时间,设置不可见  
  19.             refreshLayout.setRefreshing(false);  
  20.         }  
  21.     }, 1000);  
  22. }  

三、定义RecyclerView的Adapter

[java]  view plain  copy
 print ?
  1. public class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {  
  2.     private List<String> datas; // 数据源  
  3.     private Context context;    // 上下文Context  
  4.       
  5.     private int normalType = 0;     // 第一种ViewType,正常的item  
  6.     private int footType = 1;       // 第二种ViewType,底部的提示View  
  7.       
  8.     private boolean hasMore = true;   // 变量,是否有更多数据  
  9.     private boolean fadeTips = false// 变量,是否隐藏了底部的提示  
  10.       
  11.     private Handler mHandler = new Handler(Looper.getMainLooper()); //获取主线程的Handler  
  12.   
  13.     public MyAdapter(List<String> datas, Context context, boolean hasMore) {  
  14.         // 初始化变量  
  15.         this.datas = datas;  
  16.         this.context = context;  
  17.         this.hasMore = hasMore;  
  18.     }  
  19.       
  20.     // 获取条目数量,之所以要加1是因为增加了一条footView  
  21.     @Override  
  22.     public int getItemCount() {  
  23.         return datas.size() + 1;  
  24.     }  
  25.       
  26.     // 自定义方法,获取列表中数据源的最后一个位置,比getItemCount少1,因为不计上footView  
  27.     public int getRealLastPosition() {  
  28.         return datas.size();  
  29.     }  
  30.   
  31.   
  32.     // 根据条目位置返回ViewType,以供onCreateViewHolder方法内获取不同的Holder  
  33.     @Override  
  34.     public int getItemViewType(int position) {  
  35.         if (position == getItemCount() - 1) {  
  36.             return footType;  
  37.         } else {  
  38.             return normalType;  
  39.         }  
  40.     }  
  41.       
  42.     // 正常item的ViewHolder,用以缓存findView操作  
  43.     class NormalHolder extends RecyclerView.ViewHolder {  
  44.         private TextView textView;  
  45.   
  46.         public NormalHolder(View itemView) {  
  47.             super(itemView);  
  48.             textView = (TextView) itemView.findViewById(R.id.tv);  
  49.         }  
  50.     }  
  51.   
  52.     // // 底部footView的ViewHolder,用以缓存findView操作  
  53.     class FootHolder extends RecyclerView.ViewHolder {  
  54.         private TextView tips;  
  55.   
  56.         public FootHolder(View itemView) {  
  57.             super(itemView);  
  58.             tips = (TextView) itemView.findViewById(R.id.tips);  
  59.         }  
  60.     }  
  61.       
  62.     @Override  
  63.     public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {  
  64.         // 根据返回的ViewType,绑定不同的布局文件,这里只有两种  
  65.         if (viewType == normalType) {  
  66.             return new NormalHolder(LayoutInflater.from(context).inflate(R.layout.item, null));  
  67.         } else {  
  68.             return new FootHolder(LayoutInflater.from(context).inflate(R.layout.footview, null));  
  69.         }  
  70.     }  
  71.   
  72.     @Override  
  73.     public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) {  
  74.         // 如果是正常的imte,直接设置TextView的值  
  75.         if (holder instanceof NormalHolder) {  
  76.             ((NormalHolder) holder).textView.setText(datas.get(position));  
  77.         } else {  
  78.             // 之所以要设置可见,是因为我在没有更多数据时会隐藏了这个footView  
  79.             ((FootHolder) holder).tips.setVisibility(View.VISIBLE);  
  80.             // 只有获取数据为空时,hasMore为false,所以当我们拉到底部时基本都会首先显示“正在加载更多...”  
  81.             if (hasMore == true) {  
  82.                 // 不隐藏footView提示  
  83.                 fadeTips = false;  
  84.                 if (datas.size() > 0) {  
  85.                     // 如果查询数据发现增加之后,就显示正在加载更多  
  86.                     ((FootHolder) holder).tips.setText("正在加载更多...");  
  87.                 }  
  88.             } else {  
  89.                 if (datas.size() > 0) {  
  90.                     // 如果查询数据发现并没有增加时,就显示没有更多数据了  
  91.                     ((FootHolder) holder).tips.setText("没有更多数据了");  
  92.                       
  93.                     // 然后通过延时加载模拟网络请求的时间,在500ms后执行  
  94.                     mHandler.postDelayed(new Runnable() {  
  95.                         @Override  
  96.                         public void run() {  
  97.                             // 隐藏提示条  
  98.                             ((FootHolder) holder).tips.setVisibility(View.GONE);  
  99.                             // 将fadeTips设置true  
  100.                             fadeTips = true;  
  101.                             // hasMore设为true是为了让再次拉到底时,会先显示正在加载更多  
  102.                             hasMore = true;  
  103.                         }  
  104.                     }, 500);  
  105.                 }  
  106.             }  
  107.         }  
  108.     }  
  109.   
  110.     // 暴露接口,改变fadeTips的方法  
  111.     public boolean isFadeTips() {  
  112.         return fadeTips;  
  113.     }  
  114.   
  115.     // 暴露接口,下拉刷新时,通过暴露方法将数据源置为空  
  116.     public void resetDatas() {  
  117.         datas = new ArrayList<>();  
  118.     }  
  119.       
  120.     // 暴露接口,更新数据源,并修改hasMore的值,如果有增加数据,hasMore为true,否则为false  
  121.     public void updateList(List<String> newDatas, boolean hasMore) {  
  122.         // 在原有的数据之上增加新数据  
  123.         if (newDatas != null) {  
  124.             datas.addAll(newDatas);  
  125.         }  
  126.         this.hasMore = hasMore;  
  127.         notifyDataSetChanged();  
  128.     }  
  129.   
  130. }  

四、初始化RecyclerView


[java]  view plain  copy
 print ?
  1. private void initRecyclerView() {  
  2.     // 初始化RecyclerView的Adapter  
  3.     // 第一个参数为数据,上拉加载的原理就是分页,所以我设置常量PAGE_COUNT=10,即每次加载10个数据  
  4.     // 第二个参数为Context  
  5.     // 第三个参数为hasMore,是否有新数据  
  6.     adapter = new MyAdapter(getDatas(0, PAGE_COUNT), this, getDatas(0, PAGE_COUNT).size() > 0 ? true : false);  
  7.     mLayoutManager = new GridLayoutManager(this1);  
  8.     recyclerView.setLayoutManager(mLayoutManager);  
  9.     recyclerView.setAdapter(adapter);  
  10.     recyclerView.setItemAnimator(new DefaultItemAnimator());  
  11.   
  12.     // 实现上拉加载重要步骤,设置滑动监听器,RecyclerView自带的ScrollListener  
  13.     recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {  
  14.         @Override  
  15.         public void onScrollStateChanged(RecyclerView recyclerView, int newState) {  
  16.             super.onScrollStateChanged(recyclerView, newState);  
  17.             // 在newState为滑到底部时  
  18.             if (newState == RecyclerView.SCROLL_STATE_IDLE) {  
  19.                 // 如果没有隐藏footView,那么最后一个条目的位置就比我们的getItemCount少1,自己可以算一下  
  20.                 if (adapter.isFadeTips() == false && lastVisibleItem + 1 == adapter.getItemCount()) {  
  21.                     mHandler.postDelayed(new Runnable() {  
  22.                         @Override  
  23.                         public void run() {  
  24.                             // 然后调用updateRecyclerview方法更新RecyclerView  
  25.                             updateRecyclerView(adapter.getRealLastPosition(), adapter.getRealLastPosition() + PAGE_COUNT);  
  26.                         }  
  27.                     }, 500);  
  28.                 }  
  29.                   
  30.                 // 如果隐藏了提示条,我们又上拉加载时,那么最后一个条目就要比getItemCount要少2  
  31.                 if (adapter.isFadeTips() == true && lastVisibleItem + 2 == adapter.getItemCount()) {  
  32.                     mHandler.postDelayed(new Runnable() {  
  33.                         @Override  
  34.                         public void run() {  
  35.                             // 然后调用updateRecyclerview方法更新RecyclerView  
  36.                             updateRecyclerView(adapter.getRealLastPosition(), adapter.getRealLastPosition() + PAGE_COUNT);  
  37.                         }  
  38.                     }, 500);  
  39.                 }  
  40.             }  
  41.         }  
  42.   
  43.         @Override  
  44.         public void onScrolled(RecyclerView recyclerView, int dx, int dy) {  
  45.             super.onScrolled(recyclerView, dx, dy);  
  46.             // 在滑动完成后,拿到最后一个可见的item的位置  
  47.             lastVisibleItem = mLayoutManager.findLastVisibleItemPosition();  
  48.         }  
  49.     });  
  50. }  
  51.   
  52. // 上拉加载时调用的更新RecyclerView的方法  
  53. private void updateRecyclerView(int fromIndex, int toIndex) {  
  54.     // 获取从fromIndex到toIndex的数据  
  55.     List<String> newDatas = getDatas(fromIndex, toIndex);  
  56.     if (newDatas.size() > 0) {  
  57.         // 然后传给Adapter,并设置hasMore为true  
  58.         adapter.updateList(newDatas, true);  
  59.     } else {  
  60.         adapter.updateList(nullfalse);  
  61.     }  
  62. }  

所以,Activity的完整代码如下:

[java]  view plain  copy
 print ?
  1. public class MainActivity extends AppCompatActivity implements SwipeRefreshLayout.OnRefreshListener {  
  2.     private SwipeRefreshLayout refreshLayout;  
  3.     private RecyclerView recyclerView;  
  4.     private List<String> list;  
  5.   
  6.     private int lastVisibleItem = 0;  
  7.     private final int PAGE_COUNT = 10;  
  8.     private GridLayoutManager mLayoutManager;  
  9.     private MyAdapter adapter;  
  10.     private Handler mHandler = new Handler(Looper.getMainLooper());  
  11.   
  12.     @Override  
  13.     protected void onCreate(Bundle savedInstanceState) {  
  14.         super.onCreate(savedInstanceState);  
  15.         setContentView(R.layout.activity_main);  
  16.   
  17.         initData();  
  18.         findView();  
  19.         initRefreshLayout();  
  20.         initRecyclerView();  
  21.     }  
  22.   
  23.     private void initData() {  
  24.         list = new ArrayList<>();  
  25.         for (int i = 1; i <= 40; i++) {  
  26.             list.add("条目" + i);  
  27.         }  
  28.     }  
  29.   
  30.   
  31.     private void findView() {  
  32.         refreshLayout = (SwipeRefreshLayout) findViewById(R.id.refreshLayout);  
  33.         recyclerView = (RecyclerView) findViewById(R.id.recyclerView);  
  34.   
  35.     }  
  36.   
  37.     private void initRefreshLayout() {  
  38.         refreshLayout.setColorSchemeResources(android.R.color.holo_blue_light, android.R.color.holo_red_light,  
  39.                 android.R.color.holo_orange_light, android.R.color.holo_green_light);  
  40.         refreshLayout.setOnRefreshListener(this);  
  41.     }  
  42.   
  43.     private void initRecyclerView() {  
  44.         adapter = new MyAdapter(getDatas(0, PAGE_COUNT), this, getDatas(0, PAGE_COUNT).size() > 0 ? true : false);  
  45.         mLayoutManager = new GridLayoutManager(this1);  
  46.         recyclerView.setLayoutManager(mLayoutManager);  
  47.         recyclerView.setAdapter(adapter);  
  48.         recyclerView.setItemAnimator(new DefaultItemAnimator());  
  49.   
  50.         recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {  
  51.             @Override  
  52.             public void onScrollStateChanged(RecyclerView recyclerView, int newState) {  
  53.                 super.onScrollStateChanged(recyclerView, newState);  
  54.                 if (newState == RecyclerView.SCROLL_STATE_IDLE) {  
  55.                     if (adapter.isFadeTips() == false && lastVisibleItem + 1 == adapter.getItemCount()) {  
  56.                         mHandler.postDelayed(new Runnable() {  
  57.                             @Override  
  58.                             public void run() {  
  59.                                 updateRecyclerView(adapter.getRealLastPosition(), adapter.getRealLastPosition() + PAGE_COUNT);  
  60.                             }  
  61.                         }, 500);  
  62.                     }  
  63.   
  64.                     if (adapter.isFadeTips() == true && lastVisibleItem + 2 == adapter.getItemCount()) {  
  65.                         mHandler.postDelayed(new Runnable() {  
  66.                             @Override  
  67.                             public void run() {  
  68.                                 updateRecyclerView(adapter.getRealLastPosition(), adapter.getRealLastPosition() + PAGE_COUNT);  
  69.                             }  
  70.                         }, 500);  
  71.                     }  
  72.                 }  
  73.             }  
  74.   
  75.             @Override  
  76.             public void onScrolled(RecyclerView recyclerView, int dx, int dy) {  
  77.                 super.onScrolled(recyclerView, dx, dy);  
  78.                 lastVisibleItem = mLayoutManager.findLastVisibleItemPosition();  
  79.             }  
  80.         });  
  81.     }  
  82.   
  83.     private List<String> getDatas(final int firstIndex, final int lastIndex) {  
  84.         List<String> resList = new ArrayList<>();  
  85.         for (int i = firstIndex; i < lastIndex; i++) {  
  86.             if (i < list.size()) {  
  87.                 resList.add(list.get(i));  
  88.             }  
  89.         }  
  90.         return resList;  
  91.     }  
  92.   
  93.     private void updateRecyclerView(int fromIndex, int toIndex) {  
  94.         List<String> newDatas = getDatas(fromIndex, toIndex);  
  95.         if (newDatas.size() > 0) {  
  96.             adapter.updateList(newDatas, true);  
  97.         } else {  
  98.             adapter.updateList(nullfalse);  
  99.         }  
  100.     }  
  101.   
  102.     @Override  
  103.     public void onRefresh() {  
  104.         refreshLayout.setRefreshing(true);  
  105.         adapter.resetDatas();  
  106.         updateRecyclerView(0, PAGE_COUNT);  
  107.         mHandler.postDelayed(new Runnable() {  
  108.             @Override  
  109.             public void run() {  
  110.                 refreshLayout.setRefreshing(false);  
  111.             }  
  112.         }, 1000);  
  113.     }  
  114. }  


实现思路


一、XML的实现 


布局很简单,只有一个SwipeRefreshLayout包裹了一个RecyclerView,相信用过RecyclerView的都很容易看懂。如下为activity_main.xml:

[html]  view plain  copy
 print ?
  1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     android:layout_width="match_parent"  
  3.     android:layout_height="match_parent"  
  4.     android:orientation="vertical">  
  5.   
  6.     <android.support.v4.widget.SwipeRefreshLayout  
  7.         android:id="@+id/refreshLayout"  
  8.         android:layout_width="match_parent"  
  9.         android:layout_height="match_parent">  
  10.   
  11.         <android.support.v7.widget.RecyclerView  
  12.             android:id="@+id/recyclerView"  
  13.             android:layout_width="match_parent"  
  14.             android:layout_height="match_parent"/>  
  15.   
  16.     </android.support.v4.widget.SwipeRefreshLayout>  
  17.   
  18. </LinearLayout>  



然后,我们RecyclerView的Item布局也是非常简单,只有一个TextView。如下为item.xml:

[html]  view plain  copy
 print ?
  1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     android:layout_width="match_parent"  
  3.     android:layout_height="wrap_content"  
  4.     android:orientation="vertical">  
  5.   
  6.     <TextView  
  7.         android:id="@+id/tv"  
  8.         android:layout_width="match_parent"  
  9.         android:layout_height="120dp"  
  10.         android:background="@android:color/holo_blue_dark"  
  11.         android:gravity="center"  
  12.         android:textSize="30sp"  
  13.         android:textColor="#ffffff"  
  14.         android:text="11"  
  15.         android:layout_marginBottom="1dp"/>  
  16.   
  17. </LinearLayout>  

看到我们效果图都知道,在我们上拉时,还有一个提示的条目,我定义为 footview.xml:

[html]  view plain  copy
 print ?
  1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     android:layout_width="match_parent"  
  3.     android:layout_height="wrap_content"  
  4.     android:orientation="vertical">  
  5.   
  6.     <TextView  
  7.         android:id="@+id/tips"  
  8.         android:layout_width="match_parent"  
  9.         android:layout_height="wrap_content"  
  10.         android:gravity="center"  
  11.         android:padding="30dp"  
  12.         android:textSize="15sp"  
  13.         android:layout_marginBottom="1dp"/>  
  14.   
  15. </LinearLayout>  


二、初始化SwipeRefreshLayout


在准备好了布局文件之后,我们就把目光转到Activity中去,首先我们需要初始化SwipeRefreshLayout,初始化也是很简单,这里省去了findView操作,所以就只有设置转动的颜色,还有设置刷新的监听事件:

[java]  view plain  copy
 print ?
  1. private void initRefreshLayout() {  
  2.     refreshLayout.setColorSchemeResources(android.R.color.holo_blue_light, android.R.color.holo_red_light,  
  3.             android.R.color.holo_orange_light, android.R.color.holo_green_light);  
  4.     refreshLayout.setOnRefreshListener(this);  
  5. }  
  6.   
  7. @Override  
  8. public void onRefresh() {  
  9.     // 设置可见  
  10.     refreshLayout.setRefreshing(true);  
  11.     // 重置adapter的数据源为空  
  12.     adapter.resetDatas();  
  13.     // 获取第第0条到第PAGE_COUNT(值为10)条的数据  
  14.     updateRecyclerView(0, PAGE_COUNT);  
  15.     mHandler.postDelayed(new Runnable() {  
  16.         @Override  
  17.         public void run() {  
  18.             // 模拟网络加载时间,设置不可见  
  19.             refreshLayout.setRefreshing(false);  
  20.         }  
  21.     }, 1000);  
  22. }  

三、定义RecyclerView的Adapter

[java]  view plain  copy
 print ?
  1. public class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {  
  2.     private List<String> datas; // 数据源  
  3.     private Context context;    // 上下文Context  
  4.       
  5.     private int normalType = 0;     // 第一种ViewType,正常的item  
  6.     private int footType = 1;       // 第二种ViewType,底部的提示View  
  7.       
  8.     private boolean hasMore = true;   // 变量,是否有更多数据  
  9.     private boolean fadeTips = false// 变量,是否隐藏了底部的提示  
  10.       
  11.     private Handler mHandler = new Handler(Looper.getMainLooper()); //获取主线程的Handler  
  12.   
  13.     public MyAdapter(List<String> datas, Context context, boolean hasMore) {  
  14.         // 初始化变量  
  15.         this.datas = datas;  
  16.         this.context = context;  
  17.         this.hasMore = hasMore;  
  18.     }  
  19.       
  20.     // 获取条目数量,之所以要加1是因为增加了一条footView  
  21.     @Override  
  22.     public int getItemCount() {  
  23.         return datas.size() + 1;  
  24.     }  
  25.       
  26.     // 自定义方法,获取列表中数据源的最后一个位置,比getItemCount少1,因为不计上footView  
  27.     public int getRealLastPosition() {  
  28.         return datas.size();  
  29.     }  
  30.   
  31.   
  32.     // 根据条目位置返回ViewType,以供onCreateViewHolder方法内获取不同的Holder  
  33.     @Override  
  34.     public int getItemViewType(int position) {  
  35.         if (position == getItemCount() - 1) {  
  36.             return footType;  
  37.         } else {  
  38.             return normalType;  
  39.         }  
  40.     }  
  41.       
  42.     // 正常item的ViewHolder,用以缓存findView操作  
  43.     class NormalHolder extends RecyclerView.ViewHolder {  
  44.         private TextView textView;  
  45.   
  46.         public NormalHolder(View itemView) {  
  47.             super(itemView);  
  48.             textView = (TextView) itemView.findViewById(R.id.tv);  
  49.         }  
  50.     }  
  51.   
  52.     // // 底部footView的ViewHolder,用以缓存findView操作  
  53.     class FootHolder extends RecyclerView.ViewHolder {  
  54.         private TextView tips;  
  55.   
  56.         public FootHolder(View itemView) {  
  57.             super(itemView);  
  58.             tips = (TextView) itemView.findViewById(R.id.tips);  
  59.         }  
  60.     }  
  61.       
  62.     @Override  
  63.     public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {  
  64.         // 根据返回的ViewType,绑定不同的布局文件,这里只有两种  
  65.         if (viewType == normalType) {  
  66.             return new NormalHolder(LayoutInflater.from(context).inflate(R.layout.item, null));  
  67.         } else {  
  68.             return new FootHolder(LayoutInflater.from(context).inflate(R.layout.footview, null));  
  69.         }  
  70.     }  
  71.   
  72.     @Override  
  73.     public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) {  
  74.         // 如果是正常的imte,直接设置TextView的值  
  75.         if (holder instanceof NormalHolder) {  
  76.             ((NormalHolder) holder).textView.setText(datas.get(position));  
  77.         } else {  
  78.             // 之所以要设置可见,是因为我在没有更多数据时会隐藏了这个footView  
  79.             ((FootHolder) holder).tips.setVisibility(View.VISIBLE);  
  80.             // 只有获取数据为空时,hasMore为false,所以当我们拉到底部时基本都会首先显示“正在加载更多...”  
  81.             if (hasMore == true) {  
  82.                 // 不隐藏footView提示  
  83.                 fadeTips = false;  
  84.                 if (datas.size() > 0) {  
  85.                     // 如果查询数据发现增加之后,就显示正在加载更多  
  86.                     ((FootHolder) holder).tips.setText("正在加载更多...");  
  87.                 }  
  88.             } else {  
  89.                 if (datas.size() > 0) {  
  90.                     // 如果查询数据发现并没有增加时,就显示没有更多数据了  
  91.                     ((FootHolder) holder).tips.setText("没有更多数据了");  
  92.                       
  93.                     // 然后通过延时加载模拟网络请求的时间,在500ms后执行  
  94.                     mHandler.postDelayed(new Runnable() {  
  95.                         @Override  
  96.                         public void run() {  
  97.                             // 隐藏提示条  
  98.                             ((FootHolder) holder).tips.setVisibility(View.GONE);  
  99.                             // 将fadeTips设置true  
  100.                             fadeTips = true;  
  101.                             // hasMore设为true是为了让再次拉到底时,会先显示正在加载更多  
  102.                             hasMore = true;  
  103.                         }  
  104.                     }, 500);  
  105.                 }  
  106.             }  
  107.         }  
  108.     }  
  109.   
  110.     // 暴露接口,改变fadeTips的方法  
  111.     public boolean isFadeTips() {  
  112.         return fadeTips;  
  113.     }  
  114.   
  115.     // 暴露接口,下拉刷新时,通过暴露方法将数据源置为空  
  116.     public void resetDatas() {  
  117.         datas = new ArrayList<>();  
  118.     }  
  119.       
  120.     // 暴露接口,更新数据源,并修改hasMore的值,如果有增加数据,hasMore为true,否则为false  
  121.     public void updateList(List<String> newDatas, boolean hasMore) {  
  122.         // 在原有的数据之上增加新数据  
  123.         if (newDatas != null) {  
  124.             datas.addAll(newDatas);  
  125.         }  
  126.         this.hasMore = hasMore;  
  127.         notifyDataSetChanged();  
  128.     }  
  129.   
  130. }  

四、初始化RecyclerView


[java]  view plain  copy
 print ?
  1. private void initRecyclerView() {  
  2.     // 初始化RecyclerView的Adapter  
  3.     // 第一个参数为数据,上拉加载的原理就是分页,所以我设置常量PAGE_COUNT=10,即每次加载10个数据  
  4.     // 第二个参数为Context  
  5.     // 第三个参数为hasMore,是否有新数据  
  6.     adapter = new MyAdapter(getDatas(0, PAGE_COUNT), this, getDatas(0, PAGE_COUNT).size() > 0 ? true : false);  
  7.     mLayoutManager = new GridLayoutManager(this1);  
  8.     recyclerView.setLayoutManager(mLayoutManager);  
  9.     recyclerView.setAdapter(adapter);  
  10.     recyclerView.setItemAnimator(new DefaultItemAnimator());  
  11.   
  12.     // 实现上拉加载重要步骤,设置滑动监听器,RecyclerView自带的ScrollListener  
  13.     recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {  
  14.         @Override  
  15.         public void onScrollStateChanged(RecyclerView recyclerView, int newState) {  
  16.             super.onScrollStateChanged(recyclerView, newState);  
  17.             // 在newState为滑到底部时  
  18.             if (newState == RecyclerView.SCROLL_STATE_IDLE) {  
  19.                 // 如果没有隐藏footView,那么最后一个条目的位置就比我们的getItemCount少1,自己可以算一下  
  20.                 if (adapter.isFadeTips() == false && lastVisibleItem + 1 == adapter.getItemCount()) {  
  21.                     mHandler.postDelayed(new Runnable() {  
  22.                         @Override  
  23.                         public void run() {  
  24.                             // 然后调用updateRecyclerview方法更新RecyclerView  
  25.                             updateRecyclerView(adapter.getRealLastPosition(), adapter.getRealLastPosition() + PAGE_COUNT);  
  26.                         }  
  27.                     }, 500);  
  28.                 }  
  29.                   
  30.                 // 如果隐藏了提示条,我们又上拉加载时,那么最后一个条目就要比getItemCount要少2  
  31.                 if (adapter.isFadeTips() == true && lastVisibleItem + 2 == adapter.getItemCount()) {  
  32.                     mHandler.postDelayed(new Runnable() {  
  33.                         @Override  
  34.                         public void run() {  
  35.                             // 然后调用updateRecyclerview方法更新RecyclerView  
  36.                             updateRecyclerView(adapter.getRealLastPosition(), adapter.getRealLastPosition() + PAGE_COUNT);  
  37.                         }  
  38.                     }, 500);  
  39.                 }  
  40.             }  
  41.         }  
  42.   
  43.         @Override  
  44.         public void onScrolled(RecyclerView recyclerView, int dx, int dy) {  
  45.             super.onScrolled(recyclerView, dx, dy);  
  46.             // 在滑动完成后,拿到最后一个可见的item的位置  
  47.             lastVisibleItem = mLayoutManager.findLastVisibleItemPosition();  
  48.         }  
  49.     });  
  50. }  
  51.   
  52. // 上拉加载时调用的更新RecyclerView的方法  
  53. private void updateRecyclerView(int fromIndex, int toIndex) {  
  54.     // 获取从fromIndex到toIndex的数据  
  55.     List<String> newDatas = getDatas(fromIndex, toIndex);  
  56.     if (newDatas.size() > 0) {  
  57.         // 然后传给Adapter,并设置hasMore为true  
  58.         adapter.updateList(newDatas, true);  
  59.     } else {  
  60.         adapter.updateList(nullfalse);  
  61.     }  
  62. }  

所以,Activity的完整代码如下:

[java]  view plain  copy
 print ?
  1. public class MainActivity extends AppCompatActivity implements SwipeRefreshLayout.OnRefreshListener {  
  2.     private SwipeRefreshLayout refreshLayout;  
  3.     private RecyclerView recyclerView;  
  4.     private List<String> list;  
  5.   
  6.     private int lastVisibleItem = 0;  
  7.     private final int PAGE_COUNT = 10;  
  8.     private GridLayoutManager mLayoutManager;  
  9.     private MyAdapter adapter;  
  10.     private Handler mHandler = new Handler(Looper.getMainLooper());  
  11.   
  12.     @Override  
  13.     protected void onCreate(Bundle savedInstanceState) {  
  14.         super.onCreate(savedInstanceState);  
  15.         setContentView(R.layout.activity_main);  
  16.   
  17.         initData();  
  18.         findView();  
  19.         initRefreshLayout();  
  20.         initRecyclerView();  
  21.     }  
  22.   
  23.     private void initData() {  
  24.         list = new ArrayList<>();  
  25.         for (int i = 1; i <= 40; i++) {  
  26.             list.add("条目" + i);  
  27.         }  
  28.     }  
  29.   
  30.   
  31.     private void findView() {  
  32.         refreshLayout = (SwipeRefreshLayout) findViewById(R.id.refreshLayout);  
  33.         recyclerView = (RecyclerView) findViewById(R.id.recyclerView);  
  34.   
  35.     }  
  36.   
  37.     private void initRefreshLayout() {  
  38.         refreshLayout.setColorSchemeResources(android.R.color.holo_blue_light, android.R.color.holo_red_light,  
  39.                 android.R.color.holo_orange_light, android.R.color.holo_green_light);  
  40.         refreshLayout.setOnRefreshListener(this);  
  41.     }  
  42.   
  43.     private void initRecyclerView() {  
  44.         adapter = new MyAdapter(getDatas(0, PAGE_COUNT), this, getDatas(0, PAGE_COUNT).size() > 0 ? true : false);  
  45.         mLayoutManager = new GridLayoutManager(this1);  
  46.         recyclerView.setLayoutManager(mLayoutManager);  
  47.         recyclerView.setAdapter(adapter);  
  48.         recyclerView.setItemAnimator(new DefaultItemAnimator());  
  49.   
  50.         recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {  
  51.             @Override  
  52.             public void onScrollStateChanged(RecyclerView recyclerView, int newState) {  
  53.                 super.onScrollStateChanged(recyclerView, newState);  
  54.                 if (newState == RecyclerView.SCROLL_STATE_IDLE) {  
  55.                     if (adapter.isFadeTips() == false && lastVisibleItem + 1 == adapter.getItemCount()) {  
  56.                         mHandler.postDelayed(new Runnable() {  
  57.                             @Override  
  58.                             public void run() {  
  59.                                 updateRecyclerView(adapter.getRealLastPosition(), adapter.getRealLastPosition() + PAGE_COUNT);  
  60.                             }  
  61.                         }, 500);  
  62.                     }  
  63.   
  64.                     if (adapter.isFadeTips() == true && lastVisibleItem + 2 == adapter.getItemCount()) {  
  65.                         mHandler.postDelayed(new Runnable() {  
  66.                             @Override  
  67.                             public void run() {  
  68.                                 updateRecyclerView(adapter.getRealLastPosition(), adapter.getRealLastPosition() + PAGE_COUNT);  
  69.                             }  
  70.                         }, 500);  
  71.                     }  
  72.                 }  
  73.             }  
  74.   
  75.             @Override  
  76.             public void onScrolled(RecyclerView recyclerView, int dx, int dy) {  
  77.                 super.onScrolled(recyclerView, dx, dy);  
  78.                 lastVisibleItem = mLayoutManager.findLastVisibleItemPosition();  
  79.             }  
  80.         });  
  81.     }  
  82.   
  83.     private List<String> getDatas(final int firstIndex, final int lastIndex) {  
  84.         List<String> resList = new ArrayList<>();  
  85.         for (int i = firstIndex; i < lastIndex; i++) {  
  86.             if (i < list.size()) {  
  87.                 resList.add(list.get(i));  
  88.             }  
  89.         }  
  90.         return resList;  
  91.     }  
  92.   
  93.     private void updateRecyclerView(int fromIndex, int toIndex) {  
  94.         List<String> newDatas = getDatas(fromIndex, toIndex);  
  95.         if (newDatas.size() > 0) {  
  96.             adapter.updateList(newDatas, true);  
  97.         } else {  
  98.             adapter.updateList(nullfalse);  
  99.         }  
  100.     }  
  101.   
  102.     @Override  
  103.     public void onRefresh() {  
  104.         refreshLayout.setRefreshing(true);  
  105.         adapter.resetDatas();  
  106.         updateRecyclerView(0, PAGE_COUNT);  
  107.         mHandler.postDelayed(new Runnable() {  
  108.             @Override  
  109.             public void run() {  
  110.                 refreshLayout.setRefreshing(false);  
  111.             }  
  112.         }, 1000);  
  113.     }  
  114. }  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值