码迷,mamicode.com
首页 > 移动开发 > 详细

Android5.0新特性:RecyclerView实现上拉加载更多

时间:2016-04-16 12:12:19      阅读:569      评论:0      收藏:0      [点我收藏+]

标签:

  RecyclerView是Android5.0以后推出的新控件,相比于ListView可定制性更大,大有取代ListView之势。下面这篇博客主要来实现RecyclerView的上拉加载更多功能。

  基本思路是让RecyclerView的Adapter加载两种布局,第一个布局来显示主界面,第二个布局来显示上拉加载时的提示信息,让RecyclerView监听是否滑动到最后一个item,如果是,则调用上拉刷新的逻辑,拉取远程数据,并显示第二个布局。等加载完毕时,刷新

Adapter,并隐藏第二个布局。下面分析代码。

  要加载两种不同的布局,Adapter要重写getItemViewType方法。

  

 @Override
    public int getItemViewType(int position) {
        if (position == dataList.size())
            return 1;
        else
            return 0;
    }

  

onCreateViewHolder根据viewtype加载ViewHolder.
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view;
        if (viewType == 0) {
            view = LayoutInflater.from(context).inflate(R.layout.grid_redu_item, parent, false);
            return new NormalHolder(view);
        } else {
            view = LayoutInflater.from(context).inflate(R.layout.sample_common_list_footer, parent, false);
            mFooterHolder = new FooterHolder(view);
            return mFooterHolder;
        }
    }
注意getItemCount长度要加1。
 @Override
    public int getItemCount() {
        return dataList.size() + 1;
    }

NormalHolder
 1     class NormalHolder extends RecyclerView.ViewHolder {
 2         ImageView img;
 3         TextView name;
 4 
 5         public NormalHolder(View itemView) {
 6             super(itemView);
 7             img = (ImageView) itemView.findViewById(R.id.homepage_grid_picpic);
 8             name = (TextView) itemView.findViewById(R.id.homepage_grid_name);
 9         }
10 
11         public void setData(int position) {
12             imageLoader.displayImage(context, imgUrls[position % imgUrls.length], img);
13             name.setText(dataList.get(position));
14         }
15     }

  

FooterHolder
 1     public class FooterHolder extends RecyclerView.ViewHolder {
 2         View mLoadingViewstubstub;
 3         View mEndViewstub;
 4         View mNetworkErrorViewstub;
 5 
 6         public FooterHolder(View itemView) {
 7             super(itemView);
 8             mLoadingViewstubstub = itemView.findViewById(R.id.loading_viewstub);
 9             mEndViewstub = itemView.findViewById(R.id.end_viewstub);
10             mNetworkErrorViewstub = itemView.findViewById(R.id.network_error_viewstub);
11         }
12 
13         //根据传过来的status控制哪个状态可见
14         public void setData(LoadingFooter.FooterState status) {
15             Log.d("TAG", "reduAdapter" + status + "");
16             switch (status) {
17                 case Normal:
18                     setAllGone();
19                     break;
20                 case Loading:
21                     setAllGone();
22                     mLoadingViewstubstub.setVisibility(View.VISIBLE);
23                     break;
24                 case TheEnd:
25                     setAllGone();
26                     mEndViewstub.setVisibility(View.VISIBLE);
27                     break;
28                 case NetWorkError:
29                     setAllGone();
30                     mNetworkErrorViewstub.setVisibility(View.VISIBLE);
31                     break;
32                 default:
33                     break;
34             }
35 
36         }
37 
38         //全部不可见
39         void setAllGone() {
40             if (mLoadingViewstubstub != null) {
41                 mLoadingViewstubstub.setVisibility(View.GONE);
42             }
43             if (mEndViewstub != null) {
44                 mEndViewstub.setVisibility(View.GONE);
45             }
46             if (mNetworkErrorViewstub != null) {
47                 mNetworkErrorViewstub.setVisibility(View.GONE);
48             }
49         }
50 
51     }

  

  FooterHolder布局:

<?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:id="@+id/loading_view"
    android:layout_width="match_parent"
    android:layout_height="40dp"
    android:gravity="center"
    android:orientation="vertical"
    tools:layout_height="wrap_content">

    <include
        android:id="@+id/loading_viewstub"
        layout="@layout/sample_common_list_footer_loading"
        android:layout_width="match_parent"
        android:layout_height="40dp" />

    <include
        android:id="@+id/end_viewstub"
        layout="@layout/sample_common_list_footer_end"
        android:layout_width="match_parent"
        android:layout_height="40dp" />

    <include
        android:id="@+id/network_error_viewstub"
        layout="@layout/sample_common_list_footer_network_error"
        android:layout_width="match_parent"
        android:layout_height="40dp" />
</LinearLayout>

  显示效果:

 技术分享

  主要逻辑放在Fragment里。
  首先我们要绑定为RecyclerView绑定一个监听器,监听RecyclerView是否滑到了底部。
  Listener代码:
  
package com.yctime.truelove.LoadMore;

import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.StaggeredGridLayoutManager;
import android.view.View;

import com.yctime.truelove.ImageLoader.UILPauseOnScrollListener;

/**
 * Created by xjx
 * <p/>
 * 继承自RecyclerView.OnScrollListener,一:可以监听到是否滑动到页面最低部。二:滑动时停止加载图片
 */
public class EndlessRecyclerOnScrollListener extends UILPauseOnScrollListener {

    /**
     * 当前RecyclerView类型
     */
    protected LayoutManagerType layoutManagerType;

    /**
     * 最后一个的位置
     */
    private int[] lastPositions;

    /**
     * 最后一个可见的item的位置
     */
    private int lastVisibleItemPosition;

    /**
     * 当前滑动的状态
     */
    private int currentScrollState = 0;

    @Override
    public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
        super.onScrolled(recyclerView, dx, dy);

        RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();

        if (layoutManagerType == null) {
            if (layoutManager instanceof LinearLayoutManager) {
                layoutManagerType = LayoutManagerType.LinearLayout;
            } else if (layoutManager instanceof GridLayoutManager) {
                layoutManagerType = LayoutManagerType.GridLayout;
            } else if (layoutManager instanceof StaggeredGridLayoutManager) {
                layoutManagerType = LayoutManagerType.StaggeredGridLayout;
            } else {
                throw new RuntimeException(
                        "Unsupported LayoutManager used. Valid ones are LinearLayoutManager, GridLayoutManager and StaggeredGridLayoutManager");
            }
        }

        switch (layoutManagerType) {
            case LinearLayout:
                lastVisibleItemPosition = ((LinearLayoutManager) layoutManager).findLastVisibleItemPosition();
                break;
            case GridLayout:
                lastVisibleItemPosition = ((GridLayoutManager) layoutManager).findLastVisibleItemPosition();
                break;
            case StaggeredGridLayout:
                StaggeredGridLayoutManager staggeredGridLayoutManager = (StaggeredGridLayoutManager) layoutManager;
                if (lastPositions == null) {
                    lastPositions = new int[staggeredGridLayoutManager.getSpanCount()];
                }
                staggeredGridLayoutManager.findLastVisibleItemPositions(lastPositions);
                lastVisibleItemPosition = findMax(lastPositions);
                break;
        }
    }

    @Override
    public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
        super.onScrollStateChanged(recyclerView, newState);
        currentScrollState = newState;
        RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
        int visibleItemCount = layoutManager.getChildCount();
        int totalItemCount = layoutManager.getItemCount();
        if ((visibleItemCount > 0 && currentScrollState == RecyclerView.SCROLL_STATE_IDLE && (lastVisibleItemPosition) >= totalItemCount - 1)) {
            onLoadNextPage(recyclerView);
        }
    }

    /**
     * 取数组中最大值
     *
     * @param lastPositions
     * @return
     */
    private int findMax(int[] lastPositions) {
        int max = lastPositions[0];
        for (int value : lastPositions) {
            if (value > max) {
                max = value;
            }
        }

        return max;
    }

    public void onLoadNextPage(final View view) {
    }

    public static enum LayoutManagerType {
        LinearLayout,
        StaggeredGridLayout,
        GridLayout
    }
}
 下面是Fragment完整代码:
  1 package com.yctime.truelove.fragment;
  2 
  3 
  4 import android.support.v4.app.Fragment;
  5 import android.support.v7.widget.DefaultItemAnimator;
  6 import android.support.v7.widget.GridLayoutManager;
  7 import android.support.v7.widget.LinearLayoutManager;
  8 import android.support.v7.widget.RecyclerView;
  9 import android.util.Log;
 10 import android.view.LayoutInflater;
 11 import android.view.View;
 12 
 13 import com.yctime.truelove.LoadMore.EndlessRecyclerOnScrollListener;
 14 import com.yctime.truelove.LoadMore.LoadingFooter;
 15 import com.yctime.truelove.MainActivity;
 16 import com.yctime.truelove.Utils.NetworkUtils;
 17 import com.yctime.truelove.login.R;
 18 
 19 import java.util.ArrayList;
 20 
 21 
 22 /**
 23  * A simple {@link Fragment} subclass.
 24  */
 25 public class HomeReDuFragment extends BaseFragment {
 26 
 27     private RecyclerView mRecyclerView;
 28     private GridAdapter_Redu gridReDuAdapter;
 29     // 服务器端一共多少条数据
 30     private static final int TOTAL_COUNTER = 50;
 31     // 每一页展示多少条数据
 32     private static final int REQUEST_COUNT = 12;
 33     // 已经获取到多少条数据了
 34     private int mCurrentCounter = 0;
 35     //模拟的数据源
 36     private ArrayList<String> dataList;
 37 
 38 
 39     protected LoadingFooter.FooterState mState = LoadingFooter.FooterState.Normal;
 40 
 41     protected void setState(LoadingFooter.FooterState mState) {
 42         this.mState = mState;
 43         ((MainActivity) mContext).runOnUiThread(new Runnable() {
 44             @Override
 45             public void run() {
 46                 changeAdaperState();
 47             }
 48         });
 49     }
 50 
 51     //改变底部bottom的样式
 52     protected void changeAdaperState() {
 53         if (gridReDuAdapter != null && gridReDuAdapter.mFooterHolder != null) {
 54             gridReDuAdapter.mFooterHolder.setData(mState);
 55         }
 56     }
 57 
 58     public HomeReDuFragment() {
 59     }
 60 
 61 
 62     @Override
 63     protected View initView() {
 64         View mView = LayoutInflater.from(mContext).inflate(R.layout.homepage_viewpager_item_redu, null);
 65         mRecyclerView = (RecyclerView) mView.findViewById(R.id.home_page_recyclerview);
 66         return mView;
 67     }
 68 
 69     @Override
 70     protected void initData() {
 71         initGridView();
 72     }
 73 
 74 
 75     private View initGridView() {
 76         mRecyclerView.setHasFixedSize(true);
 77         //滑动暂停加载网络图片,而且可以监听recycler是否滑动到底部
 78         mRecyclerView.addOnScrollListener(mOnScrollListener);
 79         mRecyclerView.setItemAnimator(new DefaultItemAnimator());
 80         gridReDuAdapter = new GridAdapter_Redu(mContext);
 81         gridReDuAdapter.addAll(getRemoteData());
 82         mRecyclerView.setAdapter(gridReDuAdapter);
 83         GridLayoutManager layoutManager = new GridLayoutManager(mContext, 3);
 84         layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
 85         layoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
 86             @Override
 87             public int getSpanSize(int position) {
 88                 //如果是最后一个item,则设置占据3列,否则占据1列
 89                 boolean isFooter = position == gridReDuAdapter.getItemCount() - 1;
 90                 return isFooter ? 3 : 1;
 91             }
 92         });
 93         mRecyclerView.setLayoutManager(layoutManager);
 94         return mRecyclerView;
 95     }
 96 
 97     private EndlessRecyclerOnScrollListener mOnScrollListener = new EndlessRecyclerOnScrollListener() {
 98         @Override
 99         public void onLoadNextPage(View view) {
100             super.onLoadNextPage(view);
101 
102             if (mState == LoadingFooter.FooterState.Loading) {
103                 Log.d("@TAG", "the state is Loading, just wait..");
104                 return;
105             }
106 
107             if (mCurrentCounter < TOTAL_COUNTER) {
108                 // loading more
109                 requestData();
110                 Log.d("TAG", "请求数据");
111             } else {
112                 //the end
113                 setState(LoadingFooter.FooterState.TheEnd);
114             }
115         }
116     };
117 
118 
119     /**
120      * 模拟请求网络
121      */
122     private void requestData() {
123         setState(LoadingFooter.FooterState.Loading);
124         new Thread() {
125             @Override
126             public void run() {
127                 super.run();
128                 try {
129                     Thread.sleep(1000);
130                 } catch (InterruptedException e) {
131                     e.printStackTrace();
132                 }
133                 if (NetworkUtils.isNetAvailable(mContext)) {
134                     //模拟请求远程数据
135                     gridReDuAdapter.addAll(getRemoteData());
136                     //加载完毕时
137                     setState(LoadingFooter.FooterState.Normal);
138                     Log.d("TAG", mCurrentCounter + "");
139                 } else {
140                     //模拟一下网络请求失败的情况
141                     setState(LoadingFooter.FooterState.NetWorkError);
142                 }
143             }
144         }.start();
145     }
146 
147     //模拟请求数据
148     private ArrayList<String> getRemoteData() {
149         if (dataList == null)
150             dataList = new ArrayList<>();
151         //每次都清空一下
152         dataList.clear();
153         //要减去adapter最后一页
154         for (int i = 0; i < REQUEST_COUNT; i++) {
155             if (dataList.size() + mCurrentCounter >= TOTAL_COUNTER) {
156                 break;
157             }
158             dataList.add("账号" + (mCurrentCounter + i));
159         }
160         mCurrentCounter += dataList.size();
161         return dataList;
162     }
163 
164 
165 }
需要注意的是这个方法:
  //改变底部bottom的样式
    protected void changeAdaperState() {
        if (gridReDuAdapter != null && gridReDuAdapter.mFooterHolder != null) {
            gridReDuAdapter.mFooterHolder.setData(mState);
        }
    }
Adapter的应用调用Adapter里面的方法,来切换Adaper的样式。
  Adapter完整代码:
  1 package com.yctime.truelove.fragment;
  2 
  3 import android.content.Context;
  4 import android.content.Intent;
  5 import android.support.v7.widget.RecyclerView;
  6 import android.util.Log;
  7 import android.view.LayoutInflater;
  8 import android.view.View;
  9 import android.view.ViewGroup;
 10 import android.widget.ImageView;
 11 import android.widget.TextView;
 12 
 13 import com.yctime.truelove.ImageLoader.MyImageLoader;
 14 import com.yctime.truelove.ImageLoader.UILImageLoader;
 15 import com.yctime.truelove.LoadMore.LoadingFooter;
 16 import com.yctime.truelove.drawer.MyZoneActivity;
 17 import com.yctime.truelove.login.R;
 18 
 19 import java.util.ArrayList;
 20 
 21 
 22 public class GridAdapter_Redu extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
 23 
 24 
 25     public String[] imgUrls = {
 26             "http://img5.duitang.com/uploads/item/201402/22/20140222113830_X3ddd.jpeg",
 27             "http://v1.qzone.cc/avatar/201403/01/10/36/531147afa4197738.jpg!200x200.jpg",
 28             "http://g.hiphotos.baidu.com/zhidao/wh%3D450%2C600/sign=e4d7ed147af40ad115b1cfe7621c3de9/b7fd5266d016092445b47837d50735fae6cd340d.jpg",
 29             "http://img5q.duitang.com/uploads/item/201502/19/20150219182507_vGVaK.jpeg",
 30             "http://p1.qqyou.com/touxiang/uploadpic/2013-3/12/2013031212190118646.jpg",
 31             "http://img5.duitang.com/uploads/item/201412/08/20141208221323_YVJFk.png",
 32             "http://cdn.duitang.com/uploads/item/201408/02/20140802222651_GWuU2.png",
 33             "http://ent.dzwww.com/yulezhuanti/mtcbg/201510/W020151027467479100669.jpg",
 34             "http://p1.qqyou.com/touxiang/uploadpic/2013-3/10/2013031009323656495.jpg",
 35             "http://p1.qqyou.com/touxiang/uploadpic/2013-3/12/2013031212295986807.jpg",
 36             "http://f.hiphotos.baidu.com/zhidao/wh%3D600%2C800/sign=10742594d739b6004d9b07b1d9601912/9f2f070828381f30ec9eabdeab014c086f06f0c5.jpg",
 37             "http://a.hiphotos.baidu.com/zhidao/wh%3D600%2C800/sign=5bda8a18a71ea8d38a777c02a73a1c76/5882b2b7d0a20cf4598dc37c77094b36acaf9977.jpg",
 38             "http://a1.att.hudong.com/36/98/300001051406133039983418031.jpg"
 39     };
 40     public Context context;
 41     MyImageLoader imageLoader = new UILImageLoader();
 42     private ArrayList<String> dataList = new ArrayList<>();
 43 
 44 
 45     private final int NORMALLAYOUT = 0;
 46     private final int FOOTERLAYOUT = 1;
 47     public FooterHolder mFooterHolder;
 48 
 49     public GridAdapter_Redu(Context context) {
 50         this.context = context;
 51     }
 52 
 53     public void addAll(ArrayList<String> list) {
 54         int lastIndex = this.dataList.size();
 55         if (this.dataList.addAll(list)) {
 56             notifyItemRangeInserted(lastIndex, list.size());
 57         }
 58     }
 59 
 60     @Override
 61     public int getItemViewType(int position) {
 62         if (position == dataList.size())
 63             return FOOTERLAYOUT;
 64         else
 65             return NORMALLAYOUT;
 66     }
 67 
 68 
 69     @Override
 70     public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
 71         View view;
 72         if (viewType == NORMALLAYOUT) {
 73             view = LayoutInflater.from(context).inflate(R.layout.grid_redu_item, parent, false);
 74             return new NormalHolder(view);
 75         } else {
 76             view = LayoutInflater.from(context).inflate(R.layout.sample_common_list_footer, parent, false);
 77             mFooterHolder = new FooterHolder(view);
 78             return mFooterHolder;
 79         }
 80     }
 81 
 82     @Override
 83     public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
 84         if (holder instanceof NormalHolder) {
 85             //点击事件
 86             holder.itemView.setOnClickListener(new View.OnClickListener() {
 87                 @Override
 88                 public void onClick(View v) {
 89                     Intent intent = new Intent(context, MyZoneActivity.class);
 90                     context.startActivity(intent);
 91                 }
 92             });
 93             ((NormalHolder) holder).setData(position);
 94         }
 95     }
 96 
 97     @Override
 98     public int getItemCount() {
 99         return dataList.size() + 1;
100     }
101 
102 
103     class NormalHolder extends RecyclerView.ViewHolder {
104         ImageView img;
105         TextView name;
106 
107         public NormalHolder(View itemView) {
108             super(itemView);
109             img = (ImageView) itemView.findViewById(R.id.homepage_grid_picpic);
110             name = (TextView) itemView.findViewById(R.id.homepage_grid_name);
111         }
112 
113         public void setData(int position) {
114             imageLoader.displayImage(context, imgUrls[position % imgUrls.length], img);
115             name.setText(dataList.get(position));
116         }
117     }
118 
119     public class FooterHolder extends RecyclerView.ViewHolder {
120         View mLoadingViewstubstub;
121         View mEndViewstub;
122         View mNetworkErrorViewstub;
123 
124         public FooterHolder(View itemView) {
125             super(itemView);
126             mLoadingViewstubstub = itemView.findViewById(R.id.loading_viewstub);
127             mEndViewstub = itemView.findViewById(R.id.end_viewstub);
128             mNetworkErrorViewstub = itemView.findViewById(R.id.network_error_viewstub);
129         }
130 
131         //根据传过来的status控制哪个状态可见
132         public void setData(LoadingFooter.FooterState status) {
133             Log.d("TAG", "reduAdapter" + status + "");
134             switch (status) {
135                 case Normal:
136                     setAllGone();
137                     break;
138                 case Loading:
139                     setAllGone();
140                     mLoadingViewstubstub.setVisibility(View.VISIBLE);
141                     break;
142                 case TheEnd:
143                     setAllGone();
144                     mEndViewstub.setVisibility(View.VISIBLE);
145                     break;
146                 case NetWorkError:
147                     setAllGone();
148                     mNetworkErrorViewstub.setVisibility(View.VISIBLE);
149                     break;
150                 default:
151                     break;
152             }
153 
154         }
155 
156         //全部不可见
157         void setAllGone() {
158             if (mLoadingViewstubstub != null) {
159                 mLoadingViewstubstub.setVisibility(View.GONE);
160             }
161             if (mEndViewstub != null) {
162                 mEndViewstub.setVisibility(View.GONE);
163             }
164             if (mNetworkErrorViewstub != null) {
165                 mNetworkErrorViewstub.setVisibility(View.GONE);
166             }
167         }
168 
169     }
170 
171 }
运行效果:
技术分享

 

 

 


 


 

 

   


 


 

  

 

 

 

 

 

 

  

Android5.0新特性:RecyclerView实现上拉加载更多

标签:

原文地址:http://www.cnblogs.com/xjx22/p/5397735.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!