原生的RecyclerView.Adapter使用起来有些麻烦,所以大多数情况我们使用的是三方的adapter,比如大神hongyang的,或者BaseQuickAdapter.之前本来同事写了一个,领导说用三方的,结果现在又要用自己的.......上意难测.....所以自己写一个吧.该adapter实现了单布局,多布局,树形层级的功能
核心代码
public abstract class BaseAdapter<T> extends RecyclerView.Adapter<BaseViewHoder> {
protected List<T> mData = new ArrayList<>();
private int mLayoutId;
protected LayoutInflater mInflater;
public BaseAdapter(List<T> data, int layoutId) {
if (data != null) {
this.mData.addAll(data);
}
this.mLayoutId = layoutId;
}
@NonNull
@Override
public BaseViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
mInflater = LayoutInflater.from(viewGroup.getContext());
View view = mInflater.inflate(mLayoutId, viewGroup, false);
return new BaseViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull BaseViewHolder viewHoder, final int position) {
if (itemOnclickListener != null) {
viewHoder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
itemOnclickListener.onItemClick(position);
}
});
}
if (itemOnLongclickListener != null) {
viewHoder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
return itemOnLongclickListener.onItemLongClick(position);
}
});
}
convert(viewHoder, mData.get(position));
}
/**
* 用户实现
* @param viewHoder
* @param item
*/
public abstract void convert(BaseViewHolder viewHoder, T item);
@Override
public int getItemCount() {
return mData.size();
}
private ItemOnclickListener itemOnclickListener;
public void setItemOnclickListener(final ItemOnclickListener itemOnclickListener) {
this.itemOnclickListener = itemOnclickListener;
}
public void setNewData(List<T> data) {
this.mData.clear();
this.mData.addAll(data);
notifyDataSetChanged();
}
public T getItem(int pos) {
return mData.get(pos);
}
public void setEmptyView(int empId) {
if (mData.isEmpty()){
mLayoutId = empId;
}
}
public interface ItemOnclickListener {
void onItemClick(int position);
}
private ItemOnLongclickListener itemOnLongclickListener;
public void setItemOnLongclickListener(final ItemOnLongclickListener itemOnLongclickListener) {
this.itemOnLongclickListener = itemOnLongclickListener;
}
public interface ItemOnLongclickListener {
boolean onItemLongClick(int position);
}
}
我们加载布局资源的时候通常使用如下三个方法
View view = View.inflate(this, R.layout.activity_handler, null);
//第一个方法调用第二个方法
view = LayoutInflater.from(this).inflate(R.layout.activity_handler,null);
//第二个方法调用第三个方法,我们从这看源码
view = LayoutInflater.from(this).inflate(R.layout.activity_handler,null,false);
在RecyclerView.Adapter中我们如果使用前两个方法,会发现item布局并没有铺满RecyclerView, 这是什么原因?请参考LayoutInflater中inflate方法三个参数的区别
public class BaseViewHoder extends RecyclerView.ViewHolder {
private SparseArray<View> views = new SparseArray<>();
public BaseViewHolder(@NonNull View itemView) {
super(itemView);
}
public <T extends View> T getView(int viewId){
View view = views.get(viewId);
if (view == null){
view = itemView.findViewById(viewId);
}
return (T) view;
}
/**
* 设置文字
* @param viewId
* @param text
* @return
*/
public BaseViewHolder setText(int viewId, String text){
TextView view = getView(viewId);
view.setText(text);
return this;
}
/**
* 设置
* @param viewId
* @param check
* @return
*/
public BaseViewHolder setChecked(int viewId, boolean check){
CheckBox view = getView(viewId);
view.setChecked(check);
return this;
}
/**
* 设置gone 和 VISIBLE
* @param viewId
* @param gone
* @return
*/
public BaseViewHolder setGone(int viewId, boolean gone){
View view = getView(viewId);
view.setVisibility(gone?View.GONE:View.VISIBLE);
return this;
}
/**
* 设置INVISIBLE 和 VISIBLE
* @param viewId
* @param visible
* @return
*/
public BaseViewHolder setVisibility(int viewId, boolean visible){
View view = getView(viewId);
view.setVisibility(visible?View.VISIBLE:View.INVISIBLE);
return this;
}
/**
* 加载网络图片的时候,用户可以选择的三方框架很多,这里交给用户自己去选择
* @param viewId
* @param imageLoader
* @return
*/
public BaseViewHolder setImageUrl(int viewId, ImageLoader imageLoader){
ImageView view = getView(viewId);
if (imageLoader != null){
imageLoader.load(view,imageLoader.mUrl);
}
return this;
}
public static abstract class ImageLoader{
private String mUrl;
public ImageLoader(String mUrl) {
this.mUrl = mUrl;
}
abstract void load(ImageView imageView, String url);
}
}
使用
RecyclerView recyclerView = findViewById(R.id.recyclerView);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
BaseAdapter<Data> baseAdapter = new BaseAdapter<Data>(list, R.layout.item_adpter) {
@Override
public void convert(BaseViewHoder viewHoder, final Data item) {
viewHoder.setText(R.id.tv, item.name)
.setImageUrl(R.id.iv, new BaseViewHoder.ImageLoader(item.url) {
@Override
void load(ImageView imageView, String url) {
Glide.with(AdpterActivity.this).load(url).into(imageView);
}
});
}
};
baseAdapter.setItemOnclickListener(new BaseAdapter.ItemOnclickListener() {
@Override
public void onItemClick(int position) {
Toast.makeText(AdpterActivity.this, list.get(position).name, Toast.LENGTH_SHORT).show();
}
});
baseAdapter.setItemOnLongclickListener(new BaseAdapter.ItemOnLongclickListener() {
@Override
public boolean onItemLongClick(int position) {
Toast.makeText(AdpterActivity.this, "66666666666", Toast.LENGTH_SHORT).show();
return true;
}
});
recyclerView.setAdapter(baseAdapter);
多类型Item的BaseMultiItemAdapter
public abstract class BaseMultiItemAdapter<T extends MultiItemEntity> extends BaseAdapter<T> {
public BaseMultiItemAdapter(List<T> data) {
super(data, -1);
}
@Override
public int getItemViewType(int position) {
T t = mData.get(position);
return t.getLayoutId();
}
/**
* 通过源码可知:
* @param viewGroup
* @param viewType 是getItemViewType()方法的返回值,在这里将布局id返回
* @return
*/
public BaseViewHoder onCreateViewHolder(@NonNull ViewGroup viewGroup, int viewType) {
mInflater = LayoutInflater.from(viewGroup.getContext());
View view = null;
try {
view = mInflater.inflate(viewType, viewGroup, false);
}catch (Exception e){
//如果用户没设置layoutId,抛出异常提示用户
throw new RuntimeException("please setLayoutId in MultiItemEntity");
}
return new BaseViewHoder(view);
}
}
public interface MultiItemEntity {
/**
* 设置布局id
* @return
*/
int getLayoutId();
}
使用
public class Data implements MultiItemEntity{
String name;
String url;
@Override
public int getLayoutId() {
return R.layout.item_adpter;
}
}
BaseMultiItemAdapter baseAdapter = new BaseMultiItemAdapter<Data>(list) {
@Override
public void convert(BaseViewHoder viewHoder, Data item) {
switch (item.getLayoutId()){
case R.layout.item_adpter:
if (Integer.parseInt(item.name)%2==0) {
viewHoder.setText(R.id.tv, item.name);
}else {
viewHoder.setText(R.id.tv, "77777777777");
}
break;
}
}
};
树形多层级recycleview
public abstract class BaseTreeItemAdapter<T extends AbsTreeEntity> extends BaseMultiItemAdapter<T> {
/**
* 用来存放展开的数据
*/
private List<T> visibles = new ArrayList<>();
public BaseTreeItemAdapter(List<T> data) {
super(data);
getVisiblaData();
}
@Override
public int getItemViewType(int position) {
T t = visibles.get(position);
return t.getLayoutId();
}
@Override
public int getItemCount() {
return visibles.size();
}
private void getVisiblaData() {
if (mData==null)return;
for (T data : mData) {
//如果是根节点,直接加入
if (data.getParent() == null){
visibles.add(data);
continue;
}
//如果不是根节点,判断其父节点是否展开,展开则加入visibles集合,
// 否则将其设置为未展开,解决合起时孙子布局的现实问题
if (data.getParent().isExpand()) {
visibles.add(data);
}else {
data.setExpand(false);
}
}
}
private ItemOnclickListener itemOnclickListener;
public void setItemOnclickListener(final ItemOnclickListener itemOnclickListener) {
this.itemOnclickListener = itemOnclickListener;
}
public interface ItemOnclickListener {
void onItemClick(int position);
}
private ItemOnLongclickListener itemOnLongclickListener;
public void setItemOnLongclickListener(final ItemOnLongclickListener itemOnLongclickListener) {
this.itemOnLongclickListener = itemOnLongclickListener;
}
public interface ItemOnLongclickListener {
boolean onItemLongClick(int position);
}
@Override
public void onBindViewHolder(@NonNull BaseViewHoder viewHoder, final int position) {
if (itemOnclickListener != null) {
viewHoder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
T t = visibles.get(position);
if (t != null) {
t.setExpand(!t.isExpand());
}
visibles.clear();
getVisiblaData();
notifyDataSetChanged();
itemOnclickListener.onItemClick(position);
}
});
}
if (itemOnLongclickListener != null) {
viewHoder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
return itemOnLongclickListener.onItemLongClick(position);
}
});
}
convert(viewHoder, visibles.get(position));
}
}
其中
public abstract class AbsTreeEntity implements MultiItemEntity {
/**
* 是否展开
*/
private boolean isExpand;
/**
* 父节点
*/
private AbsTreeEntity parent;
public AbsTreeEntity getParent() {
return parent;
}
public void setParent(AbsTreeEntity parent) {
this.parent = parent;
}
public void setExpand(boolean expand) {
isExpand = expand;
}
public boolean isExpand() {
return isExpand;
}
}
使用
private List<AbsTreeEntity> getData(){
List<AbsTreeEntity> list = new ArrayList<>();
Title father = new Title("王健林","父亲");
father.setExpand(true);
list.add(father);
for (int i = 0; i < 3; i++) {
Content son = new Content("王思聪","儿子");
son.setParent(father);
son.setExpand(true);
list.add(son);
Content sun = new Content("小马","孙子");
sun.setParent(son);
list.add(sun);
}
return list;
}
class Title extends AbsTreeEntity{
String name;
String url;
public Title(String name, String url) {
this.name = name;
this.url = url;
}
public String getName() {
return name;
}
public Title setName(String name) {
this.name = name;
return this;
}
public String getUrl() {
return url;
}
public Title setUrl(String url) {
this.url = url;
return this;
}
@Override
public int getLayoutId() {
return R.layout.item_title;
}
}
class Content extends AbsTreeEntity{
String name;
String url;
public Content(String name, String url) {
this.name = name;
this.url = url;
}
public String getName() {
return name;
}
public Content setName(String name) {
this.name = name;
return this;
}
public String getUrl() {
return url;
}
public Content setUrl(String url) {
this.url = url;
return this;
}
@Override
public int getLayoutId() {
return R.layout.item_content;
}
}
RecyclerView recyclerView = findViewById(R.id.recyclerView);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
BaseTreeItemAdapter baseAdapter = new BaseTreeItemAdapter<AbsTreeEntity>(getData()) {
@Override
public void convert(BaseViewHoder viewHoder, AbsTreeEntity item) {
switch (item.getLayoutId()) {
case R.layout.item_title:
Title title = (Title) item;
viewHoder.setText(R.id.tv, title.getName() +" "+title.getUrl());
break;
case R.layout.item_content:
Content content = (Content) item;
viewHoder.setText(R.id.tv, content.getName() +" "+content.getUrl());
break;
}
}
};
baseAdapter.setItemOnclickListener(new BaseTreeItemAdapter.ItemOnclickListener() {
@Override
public void onItemClick(int position) {
Toast.makeText(TreeActivity.this, "7777777777", Toast.LENGTH_SHORT).show();
}
});
baseAdapter.setItemOnLongclickListener(new BaseTreeItemAdapter.ItemOnLongclickListener() {
@Override
public boolean onItemLongClick(int position) {
Toast.makeText(TreeActivity.this, "66666666666", Toast.LENGTH_SHORT).show();
return true;
}
});
recyclerView.setAdapter(baseAdapter);
这里需要注意的是,层级与层级之间的缩合是通过用户在布局中设置的