Android RecyclerView线性布局详解(1)
recyclerview是android 5.0新增的控件,在android-support-v7下面。官方文档对recycleview介绍很简洁到位,如下:
a flexible view for providing a limited window into a large data set.
大概意思就是说:在有限大小的窗口里显示大量数据的一个灵活的view。
下面是reccleview继承图:
看到这里我们自然想到了与之类似的控件listview,recyclerview和listview都是在有限的屏幕区域里维护少量的view来进行显示大量的数据,其实recyclerview是listview的升级版,功能更加强大,更加灵活,扩展性更强,google建议使用recycleview替代listview。
下面是recycleview结构图:
recycleview主要包括以下几个部件:
1. recyclerview.adapter
数据和视图的分离设计是程序解耦和可维护的重要指标,recycleview作为展示大量数据的view肯定是遵循这个设计的,listview也不例外。通过继承recycleview.adapter即可轻松实现自己的adapter,主要重写recycleview.adapter的下面三个方法即可实现:
public myrecycleviewadapter.myviewholder oncreateviewholder(viewgroup parent, int viewtype) public void onbindviewholder(myrecycleviewadapter.myviewholder holder, int position) public int getitemcount()
上面myrecycleviewadapter是我自己定义的viewholder
2. viewholder
viewholder用来保存列表中item view引用的类,这样做的目的是重用item视图,从而提高性能。
在listview中,viewholder不是listview自带的,是需要自己定义的,当然你也可以不使用viewholder,这样的后果就是listview每次调用getview()方法的时候都会调用findviewbyid()方法,要知道findviewbyid()性能很差,它通过递归的方式去从view树中找特定的子view的,最终往往带来很差的性能体验,所以使用viewholder也成了优化listview最重要的手段。
在recyclerview中,android内置了recyclerview.viewholder,这意味着viewholder使用成了必须。
3. 分割线 recycleview.itemdecoration
listview添加分割线很简单,只需在listview的xml中配置”divider”属性即可,如:
android:dividerheight="2dp" android:divider="@color/red"
但recycleview添加分割线是比较麻烦的,并且默认是不带分割线的。但实际开发中一般都需要分割线,使用recycleview.itemdecoration为recycleview添加分割线
4. 布局管理器 layoutmanager
recycleview支持多种布局模式:
1、linearlayoutmanager
线性布局管理器,支持水平布局和垂直布局两种
2、gridlayoutmanager
网格布局管理器
3、staggerdgridlayoutmanager
错列的网格布局管理器,可以实现瀑布流列表
recycleview使用时和listview很类似,直接看一个简单的例子,分别展示一个垂直方向和水平方向上的列表,并且都支持使用颜色和图片做分割线,效果图如下:
1. mainactivity
package com.cjl.recycleviewtest; ... public class mainactivity extends appcompatactivity { private verticalfragment mverticalfragment; private horizontalfragment mhorizontalfragment; @override protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.activity_main); //垂直 mverticalfragment = new verticalfragment(); //水平 mhorizontalfragment = new horizontalfragment(); //默认为设置垂直 getfragmentmanager().begintransaction().replace(r.id.activity_main, mverticalfragment).commit(); } @override public boolean oncreateoptionsmenu(menu menu) { menuinflater inflater = getmenuinflater(); inflater.inflate(r.menu.menu_recycleview, menu); return super.oncreateoptionsmenu(menu); } @override public boolean onoptionsitemselected(menuitem item) { int id = item.getitemid(); switch (id) { //垂直方向 case r.id.vertical: verticalfragment mverticalfragment = new verticalfragment(); getfragmentmanager().begintransaction().replace(r.id.activity_main, mverticalfragment).commit(); break; //水平方向 case r.id.horizontal: getfragmentmanager().begintransaction().replace(r.id.activity_main, mhorizontalfragment).commit(); break; } return super.onoptionsitemselected(item); } }
mainactivity布局文件 r.layout.activity_main
<?xml version="1.0" encoding="utf-8"?> <framelayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent"> </framelayout>
2. 垂直方向上 verticalfragment
public class verticalfragment extends fragment implements view.onclicklistener{ private recyclerview mrecycleviewdrawable; private recyclerview mrecycleviewcolor; private linearlayoutmanager mmanagercolor; private linearlayoutmanager mmanagerdrawable; private list<string> mdata; private button mdrawable; private button mcolor; private myrecycleviewadapter mrecycleviewadapter; @nullable @override public view oncreateview(layoutinflater inflater, viewgroup container, bundle savedinstancestate) { view view = inflater.inflate(r.layout.fragment_vertical_layout, container, false); mrecycleviewdrawable = (recyclerview) view.findviewbyid(r.id.recycleview_drawable); mrecycleviewcolor = (recyclerview) view.findviewbyid(r.id.recycleview_color); mdrawable = (button) view.findviewbyid(r.id.btn_drawable); mdrawable.setonclicklistener(this); mcolor = (button) view.findviewbyid(r.id.btn_color); mcolor.setonclicklistener(this); //1. 颜色分割线 mmanagercolor = new linearlayoutmanager(getactivity()); mmanagercolor.setorientation(linearlayoutmanager.vertical); mrecycleviewcolor.setlayoutmanager(mmanagercolor); //设置颜色分割线 mrecycleviewcolor.additemdecoration(new lineardivider(getactivity(), linearlayoutmanager.vertical, 10, this.getresources().getcolor(r.color.coloraccent))); //2. 图片分割线 mmanagerdrawable = new linearlayoutmanager(getactivity()); mmanagerdrawable.setorientation(linearlayoutmanager.vertical); mrecycleviewdrawable.setlayoutmanager(mmanagerdrawable); //设置图片分割线 drawable drawable = contextcompat.getdrawable(getactivity(), r.mipmap.divider); mrecycleviewdrawable.additemdecoration(new lineardivider(getactivity(), linearlayoutmanager.vertical, 20, drawable)); mdata = new arraylist<string>(); initdata(mdata); //自定义adapter mrecycleviewadapter = new myrecycleviewadapter(getactivity(), r.layout.item_vertical_recycleview, mdata); //设置adapter mrecycleviewcolor.setadapter(mrecycleviewadapter); mrecycleviewdrawable.setadapter(mrecycleviewadapter); return view; } private void initdata(list<string> datalist) { for (int i = 0; i < 30; i++) { datalist.add("item" + i); } } @override public void onclick(view view) { int id = view.getid(); switch (id){ case r.id.btn_drawable: mrecycleviewcolor.setvisibility(view.invisible); mrecycleviewdrawable.setvisibility(view.visible); break; case r.id.btn_color: mrecycleviewcolor.setvisibility(view.visible); mrecycleviewdrawable.setvisibility(view.invisible); break; } } }
verticalfragment 的布局文件 r.layout.fragment_vertical_layout
<?xml version="1.0" encoding="utf-8"?> <relativelayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.v7.widget.recyclerview android:id="@+id/recycleview_drawable" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginbottom="60dp"/> <android.support.v7.widget.recyclerview android:id="@+id/recycleview_color" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginbottom="60dp" android:visibility="invisible"/> <linearlayout android:id="@+id/lilayout" android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="wrap_content" android:weightsum="2" android:layout_alignparentbottom="true"> <button android:id="@+id/btn_drawable" android:layout_width="wrap_content" android:layout_height="50dp" android:text="图片分割线" android:gravity="center" android:layout_weight="1" android:background="@color/colorprimary"/> <button android:id="@+id/btn_color" android:layout_width="wrap_content" android:layout_height="50dp" android:text="颜色分割线" android:gravity="center" android:layout_weight="1" android:background="@color/mytv"/> </linearlayout> </relativelayout>
3. 直接继承recyclerview.adapter
public class myrecycleviewadapter extends recyclerview.adapter<myrecycleviewadapter.myviewholder> { private layoutinflater mlayoutinflater; private list<string> mdatalist; private int mitemlayout; public myrecycleviewadapter(context context, int itemlayout, list<string> datalist) { mlayoutinflater = layoutinflater.from(context); mitemlayout = itemlayout; mdatalist = datalist; } @override public myrecycleviewadapter.myviewholder oncreateviewholder(viewgroup parent, int viewtype) { return new myviewholder(mlayoutinflater.inflate(mitemlayout, parent, false)); } @override public void onbindviewholder(myrecycleviewadapter.myviewholder holder, int position) { holder.mtextview.settext(mdatalist.get(position)); } @override public int getitemcount() { return mdatalist.size(); } class myviewholder extends recyclerview.viewholder { private textview mtextview; public myviewholder(view itemview) { super(itemview); mtextview = (textview) itemview.findviewbyid(r.id.tv); } } }
item布局文件 item_vertical_recycleview.xml
<?xml version="1.0" encoding="utf-8"?> <framelayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content"> <textview android:id="@+id/tv" android:gravity="center" android:layout_width="match_parent" android:layout_height="60dp"/> </framelayout>
4. 分割线 recyclerview.itemdecoration
public class lineardivider extends recyclerview.itemdecoration { private drawable mdividerdarwable; private int morientation; private int mdividerhight = 1; private paint mcolorpaint; public final int[] atrrs = new int[]{ android.r.attr.listdivider }; /* orientation 方向 */ public lineardivider(context context, int orientation) { final typedarray ta = context.obtainstyledattributes(atrrs); this.mdividerdarwable = ta.getdrawable(0); ta.recycle(); setorientation(orientation); } /* int orientation 方向 int dividerhight 分割线的线宽 drawable dividerdrawable 充当分割线的图片 */ public lineardivider(context context, int orientation, int dividerhight, drawable dividerdrawable) { this(context, orientation); mdividerhight = dividerhight; mdividerdarwable = dividerdrawable; } /* int orientation 方向 int dividerhight 分割线的线宽 int dividercolor 分割线的颜色 */ public lineardivider(context context, int orientation, int dividerhight, int dividercolor) { this(context, orientation); mdividerhight = dividerhight; mcolorpaint = new paint(); mcolorpaint.setcolor(dividercolor); } public void setorientation(int orientation) { if (orientation != linearlayoutmanager.horizontal && orientation != linearlayoutmanager.vertical) { throw new illegalargumentexception("方向参数错误!"); } morientation = orientation; } @override public void ondraw(canvas c, recyclerview parent, recyclerview.state state) { super.ondraw(c, parent, state); if (morientation == linearlayoutmanager.horizontal) { drawhorizontaldivider(c, parent); } else { drawvirticaldivider(c, parent); } } //画垂直分割线 public void drawvirticaldivider(canvas c, recyclerview parent) { int left = parent.getpaddingleft(); int right = parent.getwidth() - parent.getpaddingright(); final int childcount = parent.getchildcount(); for (int i = 0; i < childcount; i++) { final view child = parent.getchildat(i); final recyclerview.layoutparams params = (recyclerview.layoutparams) child.getlayoutparams(); final int top = child.getbottom() + params.bottommargin; final int bottom = top + mdividerhight; if (mdividerdarwable != null) { mdividerdarwable.setbounds(left, top, right, bottom); mdividerdarwable.draw(c); } if (mcolorpaint != null) { c.drawrect(left, top, right, bottom, mcolorpaint); } } } //画水平分割线 public void drawhorizontaldivider(canvas c, recyclerview parent) { int top = parent.getpaddingtop(); int bottom = parent.getheight() - parent.getpaddingbottom(); final int childcount = parent.getchildcount(); for (int i = 0; i < childcount; i++) { final view child = parent.getchildat(i); recyclerview.layoutparams params = (recyclerview.layoutparams) child.getlayoutparams(); final int left = child.getright() + params.rightmargin; final int right = left + mdividerhight; if (mdividerdarwable != null) { mdividerdarwable.setbounds(left, top, right, bottom); mdividerdarwable.draw(c); } if (mcolorpaint != null) { c.drawrect(left, top, right, bottom, mcolorpaint); } } } @override public void getitemoffsets(rect outrect, view view, recyclerview parent, recyclerview.state state) { super.getitemoffsets(outrect, view, parent, state); if (morientation == linearlayoutmanager.horizontal) { outrect.set(0, 0, 0, mdividerhight); } else { outrect.set(0, 0, mdividerhight, 0); } } }
未完待续……
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
推荐阅读
-
Android RecyclerView线性布局详解(1)
-
Android RecyclerView网格布局(支持多种分割线)详解(2)
-
Android LayoutInflater加载布局详解及实例代码
-
Android布局之LinearLayout线性布局
-
Android布局之表格布局TableLayout详解
-
Android布局之绝对布局AbsoluteLayout详解
-
Android布局之帧布局FrameLayout详解
-
Android 中RecyclerView顶部刷新实现详解
-
Android编程之绝对布局AbsoluteLayout和相对布局RelativeLayout实例详解
-
Android RecyclerView网格布局(支持多种分割线)详解(2)