欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android RecycleView多种布局实现(工厂模式)

程序员文章站 2022-06-15 15:45:10
RecycleView是个很常用的控件,很多APP中都可以看到它的身影,同时它也是个很难用的控件,主要就难在多种布局的实现。 在《第一行代码—Android》这本书里边有个RecycleView实现的聊天界面布局,左右两种布局写在了同一个文件中,如果是发送来的消息,就隐藏右侧布局,反之隐藏左侧布局, ......

recycleview是个很常用的控件,很多app中都可以看到它的身影,同时它也是个很难用的控件,主要就难在多种布局的实现。

在《第一行代码—android》这本书里边有个recycleview实现的聊天界面布局,左右两种布局写在了同一个文件中,如果是发送来的消息,就隐藏右侧布局,反之隐藏左侧布局,这种方式对于比较简单的、只有两种item的界面是可行的,假如我们的item有多种布局,那么这种方式就显得很笨重。对于多种布局,我们可以使用工厂模式来实现。

 

1.首先看看效果(gif一直上传失败,只好传jpg了):

Android RecycleView多种布局实现(工厂模式)

这里的layoutmanager使用gridlayoutmanager,设置为6列,然后在adapter类中根据不同的类型来设置所占列数,具体见adapter类的setspancount方法。

 

2.然后是类图:

Android RecycleView多种布局实现(工厂模式)

 

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>