Android RecycleView多種布局實現(工廠模式)


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;
23     }
24 
25     @Override
26     public int getType() {
27         return ItemHolderFactory.ITEM_LARGE;
28     }
29 }

8.工廠類ItemHolderFactory:

三個常量表示不同的布局類型,通過getItemHolder來創建ViewHolder。

 1 public class ItemHolderFactory {
 2 
 3     public static final int ITEM_LARGE = 0;
 4     public static final int ITEM_SMALL = 1;
 5     public static final int ITEM_TITLE_BAR = 2;
 6 
 7     @IntDef({
 8             ITEM_LARGE,
 9             ITEM_SMALL,
10             ITEM_TITLE_BAR
11     })
12     @interface ItemType {}
13 
14     static ItemHolder getItemHolder(ViewGroup parent, @ItemType int type) {
15         switch (type) {
16             default:
17             case ITEM_LARGE:
18                 return new LargeItemHolder(LayoutInflater
19                         .from(parent.getContext()).inflate(R.layout.item_large, parent, false));
20             case ITEM_SMALL:
21                 return new SmallItemHolder(LayoutInflater
22                         .from(parent.getContext()).inflate(R.layout.item_small, parent, false));
23             case ITEM_TITLE_BAR:
24                 return new TitleBarItemHolder(LayoutInflater
25                         .from(parent.getContext()).inflate(R.layout.item_title_bar, parent, false));
26         }
27     }
28 }

9.ListActivity類:

 1 public class ListActivity extends AppCompatActivity {
 2 
 3     List<Item> itemList = new ArrayList<>();
 4 
 5     @Override
 6     protected void onCreate(Bundle savedInstanceState) {
 7         super.onCreate(savedInstanceState);
 8         setContentView(R.layout.activity_list);
 9 
10         initData();
11 
12         GridLayoutManager layoutManager = new GridLayoutManager(this, 6);
13         MultiListAdapter adapter = new MultiListAdapter(itemList);
14         adapter.setSpanCount(layoutManager);
15 
16         RecyclerView recyclerView = findViewById(R.id.recycle_view);
17         recyclerView.setLayoutManager(layoutManager);
18         recyclerView.setAdapter(adapter);
19     }
20 
21     private void initData() {
22         //添加數據
23         itemList.add(new ItemTitleBar("Hot New", null));
24         itemList.add(new ItemLarge(
25                 BitmapFactory.decodeResource(getResources(), R.drawable.img_1),
26                 "One More Light",
27                 "Linkin Park"));
28         itemList.add(new ItemLarge(
29                 BitmapFactory.decodeResource(getResources(), R.drawable.img_2),
30                 "Let Go ",
31                 "Avril Lavigne"));
32         itemList.add(new ItemTitleBar("Recommended", null));
33         itemList.add(new ItemSmall(
34                 BitmapFactory.decodeResource(getResources(), R.drawable.img_3),
35                 "Bridge to Terabithia"));
36         itemList.add(new ItemSmall(
37                 BitmapFactory.decodeResource(getResources(), R.drawable.img_4),
38                 "Life Is Beautiful"));
39         itemList.add(new ItemSmall(
40                 BitmapFactory.decodeResource(getResources(), R.drawable.img_5),
41                 "A Violent Flame"));
42         itemList.add(new ItemTitleBar("Top Rated", null));
43         itemList.add(new ItemLarge(
44                 BitmapFactory.decodeResource(getResources(), R.drawable.img_6),
45                 "Furious 7: Original Motion Picture Soundtrack",
46                 "Various Artists"));
47         itemList.add(new ItemLarge(
48                 BitmapFactory.decodeResource(getResources(), R.drawable.img_7),
49                 "Halo 5: Guardians (Original Soundtrack)",
50                 "Kazuma Jinnouchi"));
51     }
52 }

10.布局文件(item_large.xml):

layout_width用match_parent是為了Item在網格中居中,此處match_parent相當於寬度為Item所占的列數。

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3     xmlns:tools="http://schemas.android.com/tools"
 4     android:orientation="vertical"
 5     android:layout_width="match_parent"
 6     android:layout_height="wrap_content"
 7     android:layout_margin="4dp"
 8     android:background="#ffffff"
 9     android:elevation="2dp">
10 
11     <ImageView
12         android:contentDescription="@id/item_title"
13         android:id="@+id/item_image"
14         android:layout_width="match_parent"
15         android:layout_height="170dp"
16         android:scaleType="centerCrop"
17         tools:src="@drawable/img_7" />
18 
19     <TextView
20         android:id="@+id/item_title"
21         android:layout_width="match_parent"
22         android:layout_height="wrap_content"
23         android:layout_marginTop="8dp"
24         android:paddingStart="8dp"
25         android:paddingEnd="8dp"
26         android:lines="1"
27         android:ellipsize="end"
28         android:textColor="#000000"
29         android:textSize="18sp"
30         tools:text="Item Title" />
31 
32     <TextView
33         android:id="@+id/item_sub_title"
34         android:layout_width="match_parent"
35         android:layout_height="wrap_content"
36         android:layout_marginBottom="8dp"
37         android:paddingStart="8dp"
38         android:paddingEnd="8dp"
39         android:lines="1"
40         android:ellipsize="end"
41         android:textSize="14sp"
42         tools:text="Sub Title" />
43 
44 </LinearLayout>

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM