一、实现基本原理
利用RecyclerView的getItemViewType
方法,设置不同的item的类型,在onCreateViewHolder(parent, viewType)
方法中根据不同的viewType,设置不同的item的UI。
二、footer的添加(分页加载)
2.1 需要添加的footer
ps:要求文字部分能够动态的替换,如(点击重试、加载完成)
2.2 判断recyclerview是否滑动到最后一个
/**
* 判断当前RecyclerView是否滑动到最后
*
* @param recyclerView
* @return
*/
private boolean isSlideToBottom(RecyclerView recyclerView) {
if (recyclerView == null) {
return false;
}
if (recyclerView.computeVerticalScrollExtent() + recyclerView.computeVerticalScrollOffset() >= recyclerView.computeVerticalScrollRange()) {
return true;
}
return false;
}
2.3 针对分页加载的封装
2.3.1 希望达成的效果
- 需要分页加载的RecyclerView实现封装好的Adapter即可达成分页加载的功能
- 分页加载需要有加载下一页,点击重试,加载完成的基本功能
- 如果所有的
item <=10
(可指定),不出现footer
2.3.2 设置加载下一页的条件
2.3.3 实现代码
/**
* Created by zhufeng on 2016/8/12.
* 用于上拉加载的RecyclerView的适配器
*/
public abstract class PullToLoadAdapter extends RecyclerView.Adapter {
private final int TYPE_FOOTER = -1;
private Context mContext;
private RecyclerStatus status;
/**
* 锁住当前状态(防止多次加载)
* 在网络加载时locked = true
* 需要在网络加载成功后置为false
*/
private boolean locked = false;
/**
* 是否出现上拉加载的状态提示条
*/
private boolean pullLoadEnable = false;
private OnProgressListener onProgressListener;
private OnCompleteListener onCompleteListener;
public PullToLoadAdapter(Context mContext) {
this.mContext = mContext;
status = RecyclerStatus.NONE;
}
@Override
public int getItemCount() {
if (pullLoadEnable) {
return getItemCountChild() + 1;
} else {
return getItemCountChild();
}
}
protected abstract int getItemCountChild();
@Override
public int getItemViewType(int position) {
if (pullLoadEnable && position == getItemCountChild()) {
return TYPE_FOOTER;
}
if (getItemViewTypeChild(position) == TYPE_FOOTER) {
throw new IllegalArgumentException("type类型不能与底部条一样,请修改继承类的getItemViewTypeChild方法返回值");
}
return getItemViewTypeChild(position);
}
protected abstract int getItemViewTypeChild(int position);
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == TYPE_FOOTER) {
View contentView = LayoutInflater.from(mContext).inflate(R.layout.view_recycler_footer, parent, false);
return new FooterViewHolder(contentView);
} else {
return onCreateViewHolderChild(parent, viewType);
}
}
protected abstract RecyclerView.ViewHolder onCreateViewHolderChild(ViewGroup parent, int viewType);
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if (holder instanceof FooterViewHolder) {
((FooterViewHolder) holder).text.setText(status.getName());
if (status == RecyclerStatus.LOADING) {
((FooterViewHolder) holder).progressBar.setVisibility(View.VISIBLE);
} else {
((FooterViewHolder) holder).progressBar.setVisibility(View.GONE);
}
((FooterViewHolder) holder).text.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (onProgressListener != null) {
if (status == RecyclerStatus.ERROR) {
onProgressListener.tryAgain();
}
}
if (onCompleteListener != null) {
if (status == RecyclerStatus.COMPLETE) {
onCompleteListener.onComplete();
}
}
}
});
} else {
onBindViewHolderChild(holder, position);
}
}
protected abstract void onBindViewHolderChild(RecyclerView.ViewHolder holder, int position);
public void setLocked(boolean locked) {
if (this.locked != locked) {
this.locked = locked;
}
}
public void setStatus(RecyclerStatus status) {
if (this.status != status) {
this.status = status;
if (this.status == RecyclerStatus.NONE) {
pullLoadEnable = false;
} else {
pullLoadEnable = true;
}
}
}
public void setOnProgressListener(OnProgressListener onProgressListener) {
this.onProgressListener = onProgressListener;
}
public void setOnCompleteListener(OnCompleteListener onCompleteListener) {
this.onCompleteListener = onCompleteListener;
}
public void addBindRecyclerView(RecyclerView recyclerView) {
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
}
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
if (isSlideToBottom(recyclerView)) {
if (status == RecyclerStatus.LOADING) {
if (!locked) {
locked = true;
onProgressListener.nextPage();
}
}
}
}
});
}
/**
* 判断当前RecyclerView是否滑动到最后
*
* @param recyclerView
* @return
*/
private boolean isSlideToBottom(RecyclerView recyclerView) {
if (recyclerView == null) {
return false;
}
if (recyclerView.computeVerticalScrollExtent() + recyclerView.computeVerticalScrollOffset() >= recyclerView.computeVerticalScrollRange()) {
return true;
}
return false;
}
private class FooterViewHolder extends RecyclerView.ViewHolder {
public TextView text;
public ProgressBar progressBar;
public FooterViewHolder(View itemView) {
super(itemView);
text = (TextView) itemView.findViewById(R.id.footer);
progressBar = (ProgressBar) itemView.findViewById(R.id.progress_item);
}
}
public interface OnProgressListener {
void nextPage();
void tryAgain();
}
public interface OnCompleteListener {
void onComplete();
}
public enum RecyclerStatus {
NONE(""),
LOADING("加载中"),
ERROR("点击重试"),
COMPLETE("加载完成");
String name;
RecyclerStatus(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
}
2.3.4 使用示例
Adapter继承PullToLoadAdapter
实现onCreateViewHolderChild、onBindViewHolderChild、getItemCountChild、getItemViewTypeChild方法,分别对应RecyclerView.Adapter中的onCreateViewHolder、onBindViewHolder、getItemCount、getItemViewType,用法一样
实现adapter的setOnProgressListener方法,如:
mAdapter.setOnProgressListener(new PullToLoadAdapter.OnProgressListener() {
@Override
public void nextPage() {
//进行下一页的数据加载
}
@Override
public void tryAgain() {
//数据加载重试
}
});
- 数据加载完成时:
if(是否加载完全){
if(是否需要显示加载完成){
mAdapter.setStatus(PullToLoadAdapter.RecyclerStatus.COMPLETE);
}else{
mAdapter.setStatus(PullToLoadAdapter.RecyclerStatus.NONE);
}
}else{
mAdapter.setLocked(false);
mAdapter.setStatus(PullToLoadAdapter.RecyclerStatus.LOADING);
}
- 数据加载失败时:
mAdapter.setStatus(PullToLoadAdapter.RecyclerStatus.ERROR);
mAdapter.notifyDataSetChanged();
三、header的添加
使用getItemViewType
即可,也可以配合PullToLoadAdapter
的getItemViewTypeChild
使用。这里就不详细说明了。
四、示例代码下载
等待上传