您的位置:首页 > 其它

RecyclerView实现上拉分页加载以及下拉刷新

2017-04-30 23:09 351 查看
最近公司里提出一个需求,实现recyclerview的分页加载。之前在学校一直想实现这个功能一直没有合适的时间去研究,现在抽空实现了一个简单的Demo。

实现的功能:

第一次进入界面显示SwipeRefreshLayout的下拉刷新效果

上拉分页加载,底部显示正在加载

数据全部加载完毕后显示没有更多

效果如下



源码GIT地址,欢迎Star、Fork。

代码实现:

首先贴上RecyclerView的adapter的关键代码,在代码中有详细的注释

两个不同的ViewHolder,分别用来初始化正常的item以及脚布局。

/**
* 正常布局的ViewHolder
*/
class MyViewHolder extends RecyclerView.ViewHolder {
public MyViewHolder(View itemView) {
super(itemView);
}
}

/**
* 脚布局的ViewHolder
*/
public static class FootViewHolder extends RecyclerView.ViewHolder {

public FootViewHolder(View itemView) {
super(itemView);
}
}


这里通过重写
getItemViewType
方法来获取不同类型的布局。重写
getItemCount
,由于多加了一个脚布局所以要+1;

public int getItemViewType(int position) {
//如果position加1正好等于所有item的总和,说明是最后一个item,将它设置为脚布局
if (position + 1 == getItemCount()) {
return TYPE_FOOTER;
} else {
return TYPE_ITEM;
}
}

@Override
public int getItemCount() {
return mList.size() == 0 ? 0 : mList.size() + 1;
}


onCreateViewHolder
判断类型,以及加载不同的布局。同时在
onBindViewHolder
中进行不同情形下的处理

@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == TYPE_ITEM) {
View view = View.inflate(mContext, R.layout.list_item, null);
MyViewHolder holder = new MyViewHolder(view);
return holder;
} else if (viewType == TYPE_FOOTER) {
//脚布局
View view = View.inflate(mContext, R.layout.foot_item, null);
FootViewHolder footViewHolder = new FootViewHolder(view);
return footViewHolder;
}
return null;
}

@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if (holder instanceof MyViewHolder) {
((MyViewHolder) holder).mTextView.setText(mList.get(position));
} else if (holder instanceof FootViewHolder) {
FootViewHolder footViewHolder = (FootViewHolder) holder;
if (position == 0) {//如果第一个就是脚布局,,那就让他隐藏
footViewHolder.mProgressBar.setVisibility(View.GONE);
footViewHolder.tv_line1.setVisibility(View.GONE);
footViewHolder.tv_line2.setVisibility(View.GONE);
footViewHolder.tv_state.setText("");
}
switch (footer_state) {//根据状态来让脚布局发生改变
//              case PULL_LOAD_MORE://上拉加载
//                   footViewHolder.mProgressBar.
setVisibility(View.GONE);
//                    footViewHolder.tv_state.setText("上拉加载更多");
//                    break;
case LOADING_MORE:
footViewHolder.mProgressBar.
setVisibility(View.VISIBLE);
footViewHolder.tv_line1.setVisibility(View.GONE);
footViewHolder.tv_line2.setVisibility(View.GONE);
footViewHolder.tv_state.setText("正在加载...");
break;
case NO_MORE:
footViewHolder.mProgressBar.setVisibility(View.GONE);
footViewHolder.tv_line1.setVisibility(View.VISIBLE);
footViewHolder.tv_line2.setVisibility(View.VISIBLE);
footViewHolder.tv_state.setText("我是有底线的");
footViewHolder.tv_state.
setTextColor(Color.parseColor("#ff00ff"));
break;
}
}
}


/**
* 改变脚布局的状态的方法,在activity根据请求数据的状态来改变这个状态
*
* @param state
*/
public void changeState(int state) {
this.footer_state = state;
notifyDataSetChanged();
}


接的是在activity中实现我们所需要的效果

下拉刷新的实现,通过
SwipeRefreshLayout
,这里大家应该都比较熟悉

//设置下拉刷新的颜色
mSwipeRefreshLayout.setColorSchemeResources(R.color.colorAccent);

//第一次加载刷新
mSwipeRefreshLayout.post(new Runnable() {
@Override
public void run() {
mSwipeRefreshLayout.setRefreshing(true);
}
});

//设置下拉刷新
mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
mList.clear();
initData();
//改变foot_item的状态,这里可以根据自身的业务需求相应修改
mAdapter.changeState(1);
page = 0;
}
});


接着是分页上拉加载的实现,也是主要部分,在分页加载这里的逻辑可以根据业务的需要自己改变,我是通过页数来判断,具体的可以看源码。

//给recyclerView添加滑动监听
mRecycler.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
//判断是否在执行下拉刷新
boolean isRefreshing = mSwipeRefreshLayout.isRefreshing();
Log.d(TAG, "onScrollStateChanged: "+isRefreshing);

/*
到达底部了,如果不加!isLoading的话到达底部如果还一滑动的话就会一直进入这个方法,就一直去做请求网络的操作,这样的用户体验肯定不好.添加一个判断,每次滑倒底只进行一次网络请求去请求数据。当请求完成后,在把isLoading赋值为false,下次滑倒底又能进入这个方法了    */
if (newState == RecyclerView.SCROLL_STATE_IDLE && lastVisibleItem + 1 == mAdapter.getItemCount()  && !isLoading && !isRefreshing) {
//到达底部之后如果footView的状态不是正在加载的状态,就将 他切换成正在加载的状态
if (page < totlePage) {
Log.e("duanlian", "onScrollStateChanged: " + "进来了");
isLoading = true;
//改变状态,说明数据未全部加载完
mAdapter.changeState(1);
//延迟2秒,模拟网络请求过程
handler.postDelayed(new Runnable() {
@Override
public void run() {
getData();
page++;
}
}, 2000);
} else {
//改变状态,说明数据已经全部加载完
mAdapter.changeState(2);

}
}
}

@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
//拿到最后一个出现的item的位置
lastVisibleItem = linearLayoutManager.findLastVisibleItemPosition();
}


这里通过监听RecyclerView的滚动事件RecyclerView.OnScrollListener()实现的,它提供了两个方法:

/**
* 当RecyclerView的滑动状态改变时触发
*/
public void onScrollStateChanged(RecyclerView recyclerView, int newState){}

/**
* 当RecyclerView滑动时触发
* 类似点击事件的MotionEvent.ACTION_MOVE
*/
public void onScrolled(RecyclerView recyclerView, int dx, int dy){}


RecyclerView的滑动状态有如下三种:

/**
* The RecyclerView is not currently scrolling.
* 手指离开屏幕
*/
public static final int SCROLL_STATE_IDLE = 0;

/**
* The RecyclerView is currently being dragged by outside input such as user touch input.
* 手指触摸屏幕
*/
public static final int SCROLL_STATE_DRAGGING = 1;

/**
* The RecyclerView is currently animating to a final position while not under
* outside control.
* 手指加速滑动并放开,此时滑动状态伴随SCROLL_STATE_IDLE
*/
public static final int SCROLL_STATE_SETTLING = 2;


好了,结合代码里的注释相信你能看懂,欢迎大家批评指正QAQ。

参考资料:http://blog.csdn.net/leoleohan/article/details/50989549/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐