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

TabLayout用法详解及自定义样式

程序员文章站 2024-02-24 18:21:22
tablayout的默认样式: app:theme="@style/widget.design.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>

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用法详解及自定义样式

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);

TabLayout用法详解及自定义样式

值得注意的是:

在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;
  } 

TabLayout用法详解及自定义样式

但是tab缺没有显示任何信息,一片空白,从上面提到的tablayout的系统默认样式中我们发现: <item name="textallcaps">true</item>,这会阻止imagespan渲染出来,我们只需要将textallcaps改为false即可,如下定义,再次运行,成功显示

 <style name="customtabtextappearancestyle" parent="textappearance.design.tab">
  <item name="textallcaps">false</item>
 </style>

TabLayout用法详解及自定义样式

  修改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用法详解及自定义样式

自定义tablayout的tabitem及tabitem的点击事件

在tablayout的api是没有提供tabitem点击事件的方法,如果我们想实现如下效果图,怎么办?

TabLayout用法详解及自定义样式

先自定义一个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用法详解及自定义样式,希望对大家有所帮助