RecycleView是个很常用的控件,很多APP中都可以看到它的身影,同时它也是个很难用的控件,主要就难在多种布局的实现。
在《第一行代码—Android》这本书里边有个RecycleView实现的聊天界面布局,左右两种布局写在了同一个文件中,如果是发送来的消息,就隐藏右侧布局,反之隐藏左侧布局,这种方式对于比较简单的、只有两种Item的界面是可行的,假如我们的Item有多种布局,那么这种方式就显得很笨重。对于多种布局,我们可以使用工厂模式来实现。
Github:https://github.com/imcloudfloating/DesignApp
1.首先看看效果(GIF一直上传失败,只好传JPG了):
这里的LayoutManager使用GridLayoutManager,设置为6列,然后在Adapter类中根据不同的类型来设置所占列数,具体见Adapter类的setSpanCount方法。
2.然后是类图:
3.Adapter类:
适配器的代码很短,设置数据和绑定View的代码都写在了ItemHolder的子类里面;
List<Item>储存三种类型的Item数据,如果需要增加新的类型,只要实现Item接口就可以了;
在onBindViewHolder方法中调用ItemHolder的setData()方法来设置数据;
1 public class MultiListAdapter extends RecyclerView.Adapter<ItemHolder> { 2 3 private List<Item> mDataList; 4 5 public MultiListAdapter(List<Item> dataList) { 6 mDataList = dataList; 7 } 8 9 @NonNull 10 @Override 11 public ItemHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int type) { 12 return ItemHolderFactory.getItemHolder(viewGroup, type); 13 } 14 15 @Override 16 public void onBindViewHolder(@NonNull ItemHolder viewHolder, int i) { 17 //设置 Holder 数据 18 viewHolder.setData(mDataList.get(i)); 19 } 20 21 @Override 22 public int getItemViewType(int position) { 23 return mDataList.get(position).getType(); 24 } 25 26 @Override 27 public int getItemCount() { 28 return mDataList.size(); 29 } 30 31 public void setSpanCount(GridLayoutManager layoutManager) { 32 layoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { 33 @Override 34 public int getSpanSize(int i) { 35 int type = getItemViewType(i); 36 switch (type) { 37 default: 38 case ItemHolderFactory.ITEM_LARGE: 39 return 3; 40 case ItemHolderFactory.ITEM_SMALL: 41 return 2; 42 case ItemHolderFactory.ITEM_TITLE_BAR: 43 return 6; 44 } 45 } 46 }); 47 } 48 }
4.ItemHolder抽象类:
setData方法用来设置Item布局的数据
1 public abstract class ItemHolder extends RecyclerView.ViewHolder { 2 public ItemHolder(View item) { 3 super(item); 4 } 5 6 public abstract void setData(Item itemData); 7 }
5.LargeItemHolder类:
另外两个类似
1 public class LargeItemHolder extends ItemHolder { 2 3 private ImageView mItemImage; 4 private TextView mTitle; 5 private TextView mSubTitle; 6 7 public LargeItemHolder(View item) { 8 super(item); 9 mItemImage = item.findViewById(R.id.item_image); 10 mTitle = item.findViewById(R.id.item_title); 11 mSubTitle = item.findViewById(R.id.item_sub_title); 12 } 13 14 @Override 15 public void setData(Item itemData) { 16 ItemLarge item = (ItemLarge) itemData; 17 mItemImage.setImageBitmap(item.getImage()); 18 mTitle.setText(item.getTitle()); 19 mSubTitle.setText(item.getSubTitle()); 20 } 21 }
6.Item接口:
1 public interface Item { 2 int getType(); 3 }
7.ItemLarge类(一个图片、一个标题和一个副标题):
另外两个类似
1 public class ItemLarge implements Item { 2 3 private Bitmap mImage; 4 private String mTitle; 5 private String mSubTitle; 6 7 public ItemLarge(Bitmap bitmap, String title, String subTitle) { 8 mImage = bitmap; 9 mTitle = title; 10 mSubTitle = subTitle; 11 } 12 13 public Bitmap getImage() { 14 return mImage; 15 } 16 17 public String getTitle() { 18 return mTitle; 19 } 20 21 public String getSubTitle() { 22 return mSubTitle;