TabLayout用法详解及自定义样式
tablayout的默认样式:
app:theme="@style/widget.design.tablayout"
从系统定义的该样式继续深入:
<style name="widget.design.tablayout" parent="base.widget.design.tablayout"> <item name="tabgravity">fill</item> <item name="tabmode">fixed</item> </style> <style name="base.widget.design.tablayout" parent="android:widget"> <item name="tabmaxwidth">264dp</item> <item name="tabindicatorcolor">?attr/coloraccent</item> <item name="tabindicatorheight">2dp</item> <item name="tabpaddingstart">12dp</item> <item name="tabpaddingend">12dp</item> <item name="tabbackground">?attr/selectableitembackground</item> <item name="tabtextappearance">@style/textappearance.design.tab</item> <item name="tabselectedtextcolor">?android:textcolorprimary</item> </style>
接着,看看系统定义tab文本的样式(注意textallcaps这个属性):
<style name="textappearance.design.tab" parent="textappearance.appcompat.button"> <item name="android:textsize">14dp</item> <item name="android:textcolor">?android:textcolorsecondary</item> <item name="textallcaps">true</item> </style>
从系统定义tablayout的默认样式可以看出,我们可以改变tablayout对应的系统样式的属性值来适配我们自己的需求.
tablayout的基本用法
tablayout独立使用使用时,可以xml布局中静态添加tab个数及其样式,也可以动态添加tab的个数及其样式,如:
<android.support.design.widget.tablayout android:id="@+id/tablayout" android:background="@color/colorprimary" android:layout_width="match_parent" android:layout_height="wrap_content"> <android.support.design.widget.tabitem android:layout_width="match_parent" android:layout_height="wrap_content" android:text="android"/> <android.support.design.widget.tabitem android:layout_width="match_parent" android:layout_height="wrap_content" android:icon="@mipmap/ic_launcher"/> </android.support.design.widget.tablayout>
或者:
<android.support.design.widget.tablayout android:id="@+id/tablayout" android:background="@color/colorprimary" android:layout_width="match_parent" android:layout_height="wrap_content"/>
private int[] images = new int[]{ r.drawable.ic_account_balance_wallet_black, r.drawable.ic_android_black, r.drawable.ic_account_box_black}; private string[] tabs = new string[]{"小说", "电影", "相声"}; tablayout tablayout = (tablayout) findviewbyid(r.id.tablayout); tablayout.addtab(tablayout.newtab().seticon(images[0]).settext(tabs[0]),true); tablayout.addtab(tablayout.newtab().seticon(images[1]).settext(tabs[1]),false); tablayout.addtab(tablayout.newtab().seticon(images[2]).settext(tabs[2]),false);
tablayout在实际开发中最多的是与viewpager联合使用,实现tablayout与viewpager的联动:
<android.support.design.widget.tablayout android:id="@+id/tablayout" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@color/colorprimary" app:tabgravity="fill" app:tabindicatorcolor="@android:color/holo_orange_dark" app:tabindicatorheight="2dp" app:tabmode="fixed" app:tabselectedtextcolor="@android:color/holo_orange_dark" app:tabtextappearance="@style/customtabtextappearancestyle" app:tabtextcolor="@android:color/white" app:theme="@style/widget.design.tablayout"/> <android.support.v4.view.viewpager android:id="@+id/view_pager" android:layout_width="match_parent" android:layout_height="match_parent"/>
tablayout tablayout = (tablayout) findviewbyid(r.id.tablayout); viewpager viewpager = (viewpager) findviewbyid(r.id.view_pager); viewpager.setadapter(new tabpageradapter(getsupportfragmentmanager())); tablayout.setupwithviewpager(viewpager);
值得注意的是:
在tabpageradapter中需要实现getpagertitle()否则,tablayout的tab将不显示,先看tablayout#setupwithpager()源码,发现tab的添加是在populatefrompageradapter()中实现,实现源码如下,可以看出该方法调用了pageradpater#getpagertitle()为tab设置文本信息,如果我们自定义的adapter没有实现getpagertitle()将会导致tab不显示文本信息.
void populatefrompageradapter() { removealltabs(); if (mpageradapter != null) { final int adaptercount = mpageradapter.getcount(); for (int i = 0; i < adaptercount; i++) { addtab(newtab().settext(mpageradapter.getpagetitle(i)), false); } // make sure we reflect the currently set viewpager item if (mviewpager != null && adaptercount > 0) { final int curitem = mviewpager.getcurrentitem(); if (curitem != getselectedtabposition() && curitem < gettabcount()) { selecttab(gettabat(curitem)); } } } }
另外, 我们发现getpagertitle()方法的返回值charsequence而不是string,那么tab的文本信息的设置将变得更加灵活,比如设置一个spanablestring,将图片和文本设置tab的文本.
@override public charsequence getpagetitle(int position) { drawable image = tablayoutactivity.this.getresources().getdrawable(images[position]); image.setbounds(0, 0, image.getintrinsicwidth()/2, image.getintrinsicheight()/2); imagespan imagespan = new imagespan(image, imagespan.align_bottom); spannablestring ss = new spannablestring(" "+tabs[position]); ss.setspan(imagespan, 0, 1, spannable.span_exclusive_exclusive); return ss; }
但是tab缺没有显示任何信息,一片空白,从上面提到的tablayout的系统默认样式中我们发现: <item name="textallcaps">true</item>,这会阻止imagespan渲染出来,我们只需要将textallcaps改为false即可,如下定义,再次运行,成功显示
<style name="customtabtextappearancestyle" parent="textappearance.design.tab"> <item name="textallcaps">false</item> </style>
修改indicator的长度:
从tablayout的源码可以看出indicator的绘制,是在其内部类slidingtabstrip中绘制,而slingtabstrip类继承linearlayout,源码如下:
@override public void draw(canvas canvas) { super.draw(canvas); // thick colored underline below the current selection if (mindicatorleft >= 0 && mindicatorright > mindicatorleft) { canvas.drawrect(mindicatorleft, getheight() - mselectedindicatorheight, mindicatorright, getheight(), mselectedindicatorpaint); } }
在ondraw()中主要是就绘制一个rect,并且宽度是根据mindicatorleft和mindicatorright设置的,而mindicatorleft等的宽度来自slidingtabstrip的child,而child就相当于一个tab,这样我们就通过修改child的margin来设置mindicatorleft的值.
public void setindicator(tablayout tabs, int leftdip, int rightdip) { class<?> tablayout = tabs.getclass(); field tabstrip = null; try { tabstrip = tablayout.getdeclaredfield("mtabstrip"); } catch (nosuchfieldexception e) { e.printstacktrace(); } tabstrip.setaccessible(true); linearlayout lltab = null; try { lltab = (linearlayout) tabstrip.get(tabs); } catch (illegalaccessexception e) { e.printstacktrace(); } int left = (int) typedvalue.applydimension(typedvalue.complex_unit_dip, leftdip, resources.getsystem().getdisplaymetrics()); int right = (int) typedvalue.applydimension(typedvalue.complex_unit_dip, rightdip, resources.getsystem().getdisplaymetrics()); for (int i = 0; i < lltab.getchildcount(); i++) { view child = lltab.getchildat(i); child.setpadding(0, 0, 0, 0); linearlayout.layoutparams params = new linearlayout.layoutparams(0, linearlayout.layoutparams.match_parent, 1); params.leftmargin = left; params.rightmargin = right; child.setlayoutparams(params); child.invalidate(); } }
然后在代码中调用即可,但是要注意,必须要在tablayout渲染出来后调用,我们可以选择view.post()方法来实现:
tablayout.post(new runnable() { @override public void run() { setindicator(tablayout, 20, 20); } });
最后得到效果图如下:
自定义tablayout的tabitem及tabitem的点击事件
在tablayout的api是没有提供tabitem点击事件的方法,如果我们想实现如下效果图,怎么办?
先自定义一个tabitem:
<?xml version="1.0" encoding="utf-8"?> <linearlayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:orientation="horizontal"> <textview android:id="@+id/txt_title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:gravity="center" android:textsize="14sp" /> <imageview android:id="@+id/img_title" android:src="@drawable/indicator" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginleft="5dp" /> </linearlayout>
在自定义的adapter中可以定义一个gettabview的方法:
public view gettabview(int position){ view view = layoutinflater.from(context).inflate(r.layout.tab_item, null); textview tv= (textview) view.findviewbyid(r.id.textview); tv.settext(tabtitles[position]); imageview img = (imageview) view.findviewbyid(r.id.imageview); img.setimageresource(imageresid[position]); return view; }
重新设置点击事件:
viewpager.setadapter(pageradapter); tablayout.setupwithviewpager(viewpager); for (int i = 0; i < tablayout.gettabcount(); i++) { tablayout.tab tab = tablayout.gettabat(i); if (tab != null) { tab.setcustomview(pageradapter.gettabview(i)); if (tab.getcustomview() != null) { view tabview = (view) tab.getcustomview().getparent(); tabview.settag(i); tabview.setonclicklistener(mtabonclicklistener); } } } viewpager.setcurrentitem(1);
以上所述是小编给大家介绍的tablayout用法详解及自定义样式,希望对大家有所帮助
上一篇: c#冒泡排序示例分享
下一篇: Android触摸事件传递图解