封装RecyclerView适配器
一、上代码
1、创建CommonAdapter.java
/**
* description: RecyclerView万能的Adapter
*/
public class CommonAdapter<T> extends RecyclerView.Adapter<CommonViewHolder> {
private List<T> mList;
// 声明绑定数据接口
private OnBindDataListener<T> onBindDataListener;
// 声明绑定多类型的数据接口
private OnMoreBindDataListener<T> onMoreBindDataListener;
/**
* 构造方法
* @param mList
* @param onBindDataListener
*/
public CommonAdapter(List<T> mList, OnBindDataListener<T> onBindDataListener) {
this.mList = mList;
this.onBindDataListener = onBindDataListener;
}
/**
* 构造方法
* @param mList
* @param onMoreBindDataListener
*/
public CommonAdapter(List<T> mList, OnMoreBindDataListener<T> onMoreBindDataListener) {
this.mList = mList;
this.onBindDataListener = onMoreBindDataListener;
this.onMoreBindDataListener = onMoreBindDataListener;
}
/**
* 绑定数据接口
* @param <T>
*/
public interface OnBindDataListener<T>{
// 绑定ViewHolder
void onBindViewHolder(T model,CommonViewHolder viewHolder,int type,int position);
// 获取布局Id
int getLayoutId(int type);
}
/**
* 绑定多类型的数据接口
* @param <T>
*/
public interface OnMoreBindDataListener<T> extends OnBindDataListener<T>{
// 获取项目类型
int getItemType(int position);
}
/**
* 返回位置处项目的视图类型,以便进行视图循环。
* @param position
* @return
*/
@Override
public int getItemViewType(int position) {
if (onMoreBindDataListener != null) {
return onMoreBindDataListener.getItemType(position);
}
return 0;
}
/**
* 每当 RecyclerView 需要创建新的 ViewHolder 时,它都会调用此方法。
* 此方法会创建并初始化 ViewHolder 及其关联的 View,但不会填充视图的内容,
* 因为 ViewHolder 此时尚未绑定到具体数据。
* @param parent
* @param viewType
* @return
*/
@NonNull
@NotNull
@Override
public CommonViewHolder onCreateViewHolder(@NonNull @NotNull ViewGroup parent, int viewType) {
int layoutId = onBindDataListener.getLayoutId(viewType);
CommonViewHolder viewHolder = CommonViewHolder.getViewHolder(parent, layoutId);
return viewHolder;
}
/**
* RecyclerView 调用此方法将 ViewHolder 与数据相关联。
* 此方法会提取适当的数据,并使用该数据填充 ViewHolder 的布局。
* 例如,如果 RecyclerView 显示的是一个名称列表,该方法可能会在列表中查找适当的名称,
* 并填充 ViewHolder 的 TextView widget。
* @param holder
* @param position
*/
@Override
public void onBindViewHolder(@NonNull @NotNull CommonViewHolder holder, int position) {
onBindDataListener.onBindViewHolder(mList.get(position),holder,getItemViewType(position),position);
}
/**
* RecyclerView 调用此方法来获取数据集的大小。
* 例如,在通讯簿应用中,这可能是地址总数。
* RecyclerView 使用此方法来确定什么时候没有更多的列表项可以显示。
* @return
*/
@Override
public int getItemCount() {
return mList == null ? 0 : mList.size();
}
}
2、创建CommonViewHolder.java
/**
* description: RecyclerView万能的ViewHolder
*/
public class CommonViewHolder extends RecyclerView.ViewHolder {
// 子View的集合,使用SparseArray保存View是比较高效的
private SparseArray<View> mView;
private View mContentView;
public CommonViewHolder(@NonNull @NotNull View itemView) {
super(itemView);
mView = new SparseArray<>();
mContentView = itemView;
}
/**
* 获取CommonViewHolder实体
* @param parent
* @param layoutId
* @return
*/
public static CommonViewHolder getViewHolder(ViewGroup parent, int layoutId){
return new CommonViewHolder(View.inflate(parent.getContext(), layoutId,null));
}
/**
* 提供给外部访问View的方法
* @param viewId
* @param <T>
* @return
*/
public <T extends View>T getView(int viewId){
View view = mView.get(viewId);
if (view == null) {
view = mContentView.findViewById(viewId);
mView.put(viewId,view);
}
return (T) view;
}
/**
* 设置文本
* @param viewId
* @param text
* @return
*/
public CommonViewHolder setText(int viewId,String text){
TextView tv = getView(viewId);
tv.setText(text);
return this;
}
/**
* 设置图片链接
* @param viewId
* @param url
* @return
*/
public CommonViewHolder setImageUrl(Context context,int viewId, String url){
ImageView iv = getView(viewId);
GlideHelper.loadUrl(context,url,iv);
return this;
}
/**
* 设置图片
* @param viewId
* @param resId
* @return
*/
public CommonViewHolder setImageResource(int viewId,int resId){
ImageView iv = getView(viewId);
iv.setImageResource(resId);
return this;
}
/**
* 设置图片
* @param viewId
* @param visibility
* @return
*/
public CommonViewHolder setVisibility(int viewId,int visibility){
LinearLayout ll = getView(viewId);
ll.setVisibility(visibility);
return this;
}
}
二、使用
1、创建RecyclerView条目的布局
layout_search_user_item.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="80dp"
android:background="@android:color/white"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingLeft="15dp"
android:paddingRight="15dp">
<RelativeLayout
android:layout_width="60dp"
android:layout_height="60dp">
<de.hdodenhof.circleimageview.CircleImageView
android:id="@+id/iv_photo"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@mipmap/ic_launcher" />
<ImageView
android:id="@+id/iv_sex"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true"
android:src="@drawable/img_boy_icon" />
</RelativeLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginLeft="10dp"
android:layout_weight="1"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:id="@+id/tv_nickname"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:maxLines="1"
android:text="NickName"
android:textColor="@color/colorPrimary"
android:textStyle="bold" />
<TextView
android:id="@+id/tv_age"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:gravity="center_vertical"
android:maxLines="1"
android:text="Age" />
</LinearLayout>
<LinearLayout
android:visibility="gone"
android:id="@+id/ll_contact_info"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/tv_contact_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="name" />
<TextView
android:id="@+id/tv_contact_phone"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:text="phone" />
</LinearLayout>
<TextView
android:id="@+id/tv_desc"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:ellipsize="marquee"
android:gravity="center_vertical"
android:marqueeRepeatLimit="marquee_forever"
android:singleLine="true"
android:text="Desc" />
</LinearLayout>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/img_right_arrow" />
</LinearLayout>
</RelativeLayout>
layout_search_title_item.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:textSize="16sp"
android:textColor="@android:color/white"
android:paddingLeft="15dp"
android:gravity="center_vertical"
android:background="@color/colorAccent"
android:id="@+id/tv_title"
android:layout_width="match_parent"
android:layout_height="50dp" />
</RelativeLayout>
2、创建RecyclerView的数据模型
AddFriendModel.java
/**
* description: 数据模型
*/
public class AddFriendModel {
//类型
private int type;
//标题
private String title;
//内容
private String userId;
private String photo;
private boolean sex;
private int age;
private String nickName;
private String desc;
//联系人
private boolean isContact = false;
private String contactName;
private String contactPhone;
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getPhoto() {
return photo;
}
public void setPhoto(String photo) {
this.photo = photo;
}
public boolean isSex() {
return sex;
}
public void setSex(boolean sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getNickName() {
return nickName;
}
public void setNickName(String nickName) {
this.nickName = nickName;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
public boolean isContact() {
return isContact;
}
public void setContact(boolean contact) {
isContact = contact;
}
public String getContactName() {
return contactName;
}
public void setContactName(String contactName) {
this.contactName = contactName;
}
public String getContactPhone() {
return contactPhone;
}
public void setContactPhone(String contactPhone) {
this.contactPhone = contactPhone;
}
}
3、在布局文件中添加RecyclerView控件
activity_add_friend.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/mSearchResultView"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
</LinearLayout>
4、开始使用
4.2、单个类型
// RecyclerView适配器
private CommonAdapter<AddFriendModel> mCommonAdapter;
// RecyclerView数据源
private List<AddFriendModel> mList = new ArrayList<>();
@Override
protected void initView() {
// RecyclerView设置布局管理器
binding.mContactView.setLayoutManager(new LinearLayoutManager(this));
// 添加列表项下划线
binding.mContactView.addItemDecoration(new DividerItemDecoration(this,DividerItemDecoration.VERTICAL));
// 设置适配器
mCommonAdapter = new CommonAdapter<>(mList, new CommonAdapter.OnBindDataListener<AddFriendModel>() {
@Override
public void onBindViewHolder(AddFriendModel model, CommonViewHolder viewHolder, int type, int position) {
// 设置头像
viewHolder.setImageUrl(ContactFriendActivity.this,R.id.iv_photo,model.getPhoto());
// 设置性别
viewHolder.setImageResource(R.id.iv_sex,model.isSex() ? R.drawable.img_boy_icon : R.drawable.img_girl_icon);
// 设置昵称
viewHolder.setText(R.id.tv_nickname,model.getNickName());
//点击事件
viewHolder.itemView.setOnClickListener(v -> {});
}
@Override
public int getLayoutId(int type) {
return R.layout.layout_search_user_item;
}
});
binding.mContactView.setAdapter(mCommonAdapter);
}
4.1、多个类型
// 标题
public static final int TYPE_TITLE = 0;
// 内容
public static final int TYPE_CONTENT = 1;
// RecyclerView适配器
private CommonAdapter<AddFriendModel> mAddFriendAdapter;
// RecyclerView数据源
private List<AddFriendModel> mList = new ArrayList<>();
@Override
protected void initView() {
// 列表的实现
// RecyclerView设置布局管理器
binding.mSearchResultView.setLayoutManager(new LinearLayoutManager(this));
// 添加列表项下划线
binding.mSearchResultView.addItemDecoration(new DividerItemDecoration(this,DividerItemDecoration.VERTICAL));
// 设置适配器
mAddFriendAdapter = new CommonAdapter<AddFriendModel>(mList, new CommonAdapter.OnMoreBindDataListener<AddFriendModel>() {
@Override
public int getItemType(int position) {
return mList.get(position).getType();
}
@Override
public void onBindViewHolder(AddFriendModel model, CommonViewHolder viewHolder, int type, int position) {
if (model.getType() == TYPE_TITLE){
// 设置标题
viewHolder.setText(R.id.tv_title,model.getTitle());
}else if (model.getType() == TYPE_CONTENT){
// 设置头像
viewHolder.setImageUrl(AddFriendActivity.this,R.id.iv_photo,model.getPhoto());
// 设置性别
viewHolder.setImageResource(R.id.iv_sex,model.isSex() ? R.drawable.img_boy_icon : R.drawable.img_girl_icon);
// 设置昵称
viewHolder.setText(R.id.tv_nickname,model.getNickName());
//点击事件
viewHolder.itemView.setOnClickListener(v -> {});
}
}
@Override
public int getLayoutId(int type) {
if (type == TYPE_TITLE) {
return R.layout.layout_search_title_item;
}else if (type == TYPE_CONTENT){
return R.layout.layout_search_user_item;
}
return 0;
}
});
// 添加适配器
binding.mSearchResultView.setAdapter(mAddFriendAdapter);
}
三、效果图
1、单个类型
2、多个类型
四、注意事项
1、ViewBinding官方教程:链接。
2、RecyclerView官方教程:链接。
3、TYPE_TITLE 和 TYPE_CONTENT 在使用前就设置到AddFriendModel里了,所以直接使用getType()方法是有数据的。