继承RecyclerView.Adapter
,并在内部自定义对应的ViewHolder
public class HelloRecyclerAdapter extends RecyclerView.Adapter<HelloRecyclerAdapter.ViewHolder> {
private List dataList = new ArrayList();
public HelloRecyclerAdapter(List dataList) {
this.dataList = dataList;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_hello_recycler, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
Object data = dataList.get(position);
//把data的数据赋值到holder对应的View中
}
@Override
public int getItemCount() {
return dataList.size();
}
class ViewHolder extends RecyclerView.ViewHolder {
public ViewHolder(View itemView) {
super(itemView);
}
}
}
Activity
中新建adapter
并赋值给recycler
recyclerView.setLayoutManager(new LinearLayoutManager(this));
//list是已赋值数据
recyclerView.setAdapter(new HelloRecyclerAdapter(list));
以上,一个recyclerView
的列表就出来了。
RecyclerView
中添加header
先定义两个常量,用来区分header
和普通情况
private static final int HEADER = 1;
private static final int NORMAL = 2;
建立另一个HeaderViewHolder
class HeaderViewHolder extends RecyclerView.ViewHolder {
public HeaderViewHolder(View itemView) {
super(itemView);
}
}
然后onCreateViewHolder
中分情况创建
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view;
if (viewType == HEADER) {
view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_hello_recycler, parent, false);
} else {
view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_hello_recycler_head, parent, false)
}
return new ViewHolder(view);
}
getItemCount
中增加对应数量
@Override
public int getItemCount() {
//增加header节点
return dataList.size() + 1;
}
onBindViewHolder
中分情况绑定数据
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
Object data = dataList.get(position);
if (holder instanceof HeaderViewHolder) {
//绑定header数据
} else {
//绑定普通数据
}
}
当然这只是最基本的能用了,在使用过程中会遇到一些奇奇怪怪的问题,接下来我们一一解决
recyclerView
中数据错乱问题数据来源固定
这种情况很好解决,主要就是每个item
在赋值时候,要把各个情况都覆盖到,不能只覆盖一种情况。
假设item
内有收藏功能,收藏后会用UI的变化,我们可以用如下方法实现:
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
Object data = dataList.get(position);
//这里一定不能只写if而不写else,否则会出现颜色错乱
if(data.isCollection()){
holder.collectionView.setTextColor(RED)
}else{
holder.collectionView.setTextColor(BLACK)
}
}
数据来自网络
这类情况的常见情景是加载图片,当网络环境较差时,图片加载完后,你可能已经翻页了,这时候再去显示图片会出现错乱的情况。
针对这一情况,我们可以给图片添加一个TAG,显示图片时候判断对应的TAG是否一致
holder.ivCameraImages.setBackground(R.drawable.place_holder);
holder.ivCameraImages.setTag(imageURL);
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (msg.what == MSG_IMAGE) {
Bitmap bm = (Bitmap) msg.obj;
if (bm != null) {
if (TextUtils.equals((String) imageView.getTag(), imageURL)){
imageView.setBackground(new BitmapDrawable(bm));
}
}
}
}
当然,目前的主流图片框架会把url作为对应的TAG添加到ImageView中,省了我们重复造轮子的时间。
RecyclerView
中的局部刷新还是回到那个收藏的问题,如果点击收藏按钮,只更新当前的item
这个需求如何实现?
当列表中没有图片时候
public void collectionSuccess(String id) {
//当header的收藏数量变化时候
//通过ID找到下标
int position = findPositionForId(id);
//更新数量
dataList.get(position)
.setCollectionNum(data.getCollectionNum()+1);
//更新对应UI
notifyItemChanged(position);
}
列表中存在图片时
当有图片时候,使用notifyItemChanged()
方法会导致图片闪烁。
解决这个问题呢就需要进行一些大的改动了。
首先,放弃使用两个参数的onBindViewHolder
方法,使用三个参数的方法:
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
//不去覆写这个方法
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position, List<Object> payloads) {
if (payLoads != null && payLoads.size() > 0) {
//有部分数据更新的情况
String s = (String) payLoads.get(0);
switch (s) {
case STAR:
//点赞数量UI更新
updateStar(holder, dataList.get(position - 1));
break;
case COLLECTION:
//收藏数量UI更新
updateCollection(holder, dataList.get(position - 1));
break;
}
} else {
//正常情况
}
}
然后,数据发生改变时,调用的方法也有变化
public void collectionSuccess(String id) {
//当header的收藏数量变化时候
//通过ID找到下标
int position = findPositionForId(id);
//更新数量
dataList.get(position).setCollectionNum(data.getCollectionNum()+1);
//更新对应UI
notifyItemChanged(position,COLLECTION);
}
这样设置完后,局部更新数据就不会导致item有变化了。
最后,我把整个带Heade
r的,可以局部更新UI的adapter
基本框架都放出来,大家有需要的自行取用
完整结构
public class HelloRecyclerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private static final int HEADER = 1;
private static final int NORMAL = 2;
private static final String COLLECTION = "collection";
private static final String STAR = "star";
private Context context;
private Object headData;
private List dataList;
public HelloRecyclerAdapter(Context mContext,
Object headerData,
List answerList) {
this.context = mContext;
this.headData = headerData;
this.dataList = answerList;
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == HEADER) {
View view = LayoutInflater.from(context)
.inflate(R.layout.item_header_view, parent, false);
return new HeaderViewHolder(view);
} else {
View view = LayoutInflater.from(context)
.inflate(R.layout.item_normal_view, parent, false);
return new NormalViewHolder(view);
}
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
//不去覆写这个方法
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position, List<Object> payloads) {
if (holder instanceof HeaderViewHolder) {
bindHeaderView((HeaderViewHolder) holder, payloads);
} else {
bindNormalView((NormalViewHolder) holder, position, payloads);
}
}
private void bindHeaderView(HeaderViewHolder holder, List<Object> payLoads) {
if (payLoads != null && payLoads.size() > 0) {
String payLoad = (String) payLoads.get(0);
switch (payLoad) {
case COLLECTION:
//header收藏数量更新
updateCollection(holder);
break;
case STAR:
//header点赞数量更新
updateStar(holder);
break;
}
} else {
//正常绑定数据
}
}
private void bindNormalView(NormalViewHolder holder, int position, List<Object> payLoads) {
if (payLoads != null && payLoads.size() > 0) {
String s = (String) payLoads.get(0);
switch (s) {
case STAR:
//点赞数量更新
updateStar(holder, dataList.get(position - 1));
break;
case COLLECTION:
//收藏数量更新
updateCollection(holder, dataList.get(position - 1));
break;
}
} else {
//绑定正常数据
}
}
@Override
public int getItemCount() {
return dataList.size() + 1;
}
@Override
public int getItemViewType(int position) {
if (position == 0) {
return HEADER;
} else {
return NORMAL;
}
}
public void collectionSuccess(String id) {
//当header的收藏数量变化时候
//通过ID找到下标
int position = findPositionForId(id);
//更新数量
dataList.get(position).setCollectionNum(data.getCollectionNum()+1);
//更新对应UI
notifyItemChanged(position,COLLECTION);
}
public void disCollectionSuccess(String id) {
//当header的收藏数量变化时候
notifyItemChanged(0, COLLECTION);
}
public void starSuccess(String id) {
int position = 0;
//略去通过ID寻找position过程
//略去通过ID更改对应数据的点赞数量
notifyItemChanged(position, STAR);
}
public void disStarSuccess(String id) {
int position = 0;
//略去通过ID寻找position过程
//略去通过ID更改对应数据的点赞数量
notifyItemChanged(position, STAR);
}
class HeaderViewHolder extends RecyclerView.ViewHolder {
public HeaderViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
}
class NormalViewHolder extends RecyclerView.ViewHolder {
public NormalViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
}
}