最近遇到一个需求:会话列表页面需要能动态添加一个可高度定制的Item。小小总结下自己的实现方式。
一般情况下,在RecyclerView中我们引进不同的Item类型,都是提前确定好的,那如果遇到不确定类型的Item,如何处理?
那么就需要可以动态添加,灵活抽插,才是王道。
Adapter类封装:
public abstract class BaseAdapter<D extends Data> extends RecyclerView.Adapter<BaseHolder> {
private List<D> mList;
private OnRecyclerViewItemClickListener clickListener;
private OnRecyclerViewItemLongClickListener longClickListener;
public BaseAdapter(List<D> list) {
this.mList = list;
}
@Override
public int getItemViewType(int position) {
return mList == null ? 0 : mList.get(position).getType();
}
@NonNull
@Override
public BaseHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
BaseHolder baseHolder = null;
/*以下调用带参的构造函数*/
Constructor constructor = null;
try {
constructor = getViewHolderClass(viewType).getDeclaredConstructor(new Class[]{View.class});
constructor.setAccessible(true);
baseHolder = (BaseHolder) constructor.newInstance(getItemView(parent, viewType));
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return baseHolder;
}
protected View getItemView(@NonNull ViewGroup parent, int viewType) {
View view = null;
view = LayoutInflater.from(parent.getContext()).inflate(getLayoutRes(viewType), parent, false);
return view;
}
protected abstract @LayoutRes int getLayoutRes(int viewType);
protected abstract Class<? extends BaseHolder> getViewHolderClass(int viewType);
@Override
public void onBindViewHolder(@NonNull BaseHolder holder, final int position) {
holder.bindData(mList.get(position));
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (clickListener != null) {
clickListener.onClick(v, position);
}
}
});
holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
if (longClickListener != null) {
longClickListener.onLongClick(v, position);
return true;
} else
return false;
}
});
}
@Override
public int getItemCount() {
return mList == null ? 0 : mList.size();
}
public void addOnRecyclerViewItemClickListener(OnRecyclerViewItemClickListener clickListener) {
this.clickListener = clickListener;
}
public void addOnRecyclerViewItemLongClickListener(OnRecyclerViewItemLongClickListener longClickListener) {
this.longClickListener = longClickListener;
}
public D getItemData(int position) {
return mList == null ? null : mList.get(position);
}
}
BaseHolder
public abstract class BaseHolder<D extends Data> extends RecyclerView.ViewHolder {
public BaseHolder(View itemView) {
super(itemView);
}
protected abstract void bindData(@NonNull D data);
}
Data是一个简单接口仅用于区分Item类型(列表中数据对象需实现)
public interface Data {
int getType();
}
以上是RecyclerView使用Adapter的基础封装,正常使用直接继承即可,如:
public class TestAdapter extends BaseAdapter<User> {
public TestAdapter(List<User> list) {
super(list);
}
@Override
protected int getLayoutRes(int viewType) {
return R.layout.user_item_layout;
}
@Override
protected Class<? extends BaseHolder> getViewHolderClass(int viewType) {
switch (viewType){
case 1:
return UserHolder.class;
case 2:
return UserTwoHolder.class;
}
return UserHolder.class;
}
}
简单的多类型直接使用即可。
下面动态添加,继承上面的BaseAdapter,如下:
public class SuperBaseAdapter<D extends Data> extends BaseAdapter<D> {
public SuperBaseAdapter(List<D> list) {
super(list);
}
@Override
protected int getLayoutRes(int viewType) {
return ItemUtils.getIntance().getLayoutRes(viewType);
}
@Override
protected Class<? extends BaseHolder> getViewHolderClass(int viewType) {
return ItemUtils.getIntance().getViewHolderClass(viewType);
}
}
其中动态添加主要使用ItemUtils来处理:
public class ItemUtils {
private static ItemUtils itemUtils;
private SparseArray<Class<? extends BaseHolder>> sparseArrayItems;
private SparseIntArray sparseArrayLayoutRes;
private ItemUtils(){
sparseArrayItems = new SparseArray<>();
sparseArrayLayoutRes = new SparseIntArray();
}
public static ItemUtils getIntance(){
if (itemUtils == null){
synchronized (ItemUtils.class){
if (itemUtils == null){
itemUtils = new ItemUtils();
}
}
}
return itemUtils;
}
public void addViewHolderItem(int viewType, @LayoutRes int layoutRes, Class<? extends BaseHolder> c){
sparseArrayLayoutRes.put(viewType,layoutRes);
sparseArrayItems.put(viewType,c);
}
protected int getLayoutRes(int viewType) {
return sparseArrayLayoutRes.get(viewType);
}
protected Class<? extends BaseHolder> getViewHolderClass(int viewType) {
return sparseArrayItems.get(viewType);
}
}
具体例子:
public class MainActivity extends AppCompatActivity {
private RecyclerView recyclerView;
private List<User> mList = new ArrayList<>();
// private TestAdapter adapter;
private TestSuperAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView = findViewById(R.id.recycler_view);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
// adapter = new TestAdapter(mList);
ItemUtils.getIntance().addViewHolderItem(1, R.layout.user_item_layout, UserHolder.class);
ItemUtils.getIntance().addViewHolderItem(2, R.layout.user_item_layout, UserTwoHolder.class);
adapter = new TestSuperAdapter(mList);
recyclerView.setAdapter(adapter);
}
@Override
protected void onResume() {
super.onResume();
mList.clear();
for (int i = 0; i < 20; i++) {
User user = new User();
if (i % 2 == 0) {
user.setType(2);
} else
user.setType(1);
user.setName("skwen" + (Math.random() * 30));
user.setAge((int) (Math.random() * 30));
mList.add(user);
}
adapter.notifyDataSetChanged();
}
}
其中TestSuperAdapter知识继承了SuperBaseAdapter,未做任何处理。
整体就是使用ItemUtils类动态添加相应类型的Item即可。
ItemUtils的add方法,参数说明一下,
1 viewholder类型或者数据中携带的类型(不同数据不同viewHolder)
2 对应viewholder的布局文件id
3 viewholder的类
基本上简单的实现的RecyclerView的Item动态添加,其它功能可自行拓展。