TabLayout使用详解

本文详细介绍了Android中TabLayout的使用,包括基本配置、属性调整、与ViewPager结合使用、自定义视图以及如何改变指示器长度。通过实例展示了如何创建带有图片和文字的标签,以及如何在文字大写的情况下正确显示ImageSpan。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

TabLayout 标签布局

谷歌在Material Design中推出TabLayout以替代开源库PagerSlidingTabStrip和ViewPagerIndicator的使用。事实上,这类indicator指示器的布局可谓是Android中最常见的布局设计了,TabLayout的出现给我们带来一定便利,它的使用对开发者更加友好,并且和Toolbar一样,配合material design的其他控件使用能轻易创造出酷炫的效果。

关联点

主要讲下继承,默认样式,api等等

继承

从继承关系我们可以看到TabLayout直接继承HorizontalScrollView,所以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对应的系统样式的属性值来适配我们自己的需求.

属性及api

app:tabMinWidth             Tab的最小宽度
app:tabMaxWidth             Tab的最大宽度
app:tabMode                 Tab模式,默认是fixed:固定的,标签很多时候会被挤压,不能滑动
app:tabGravity              "center"//居中,如果是"fill",则是填充满
app:tabContentStart         TabLayout左边位置的偏移量
app:tabPadding              Tab内部的子控件的Padding
app:tabPaddingStart         左
app:tabPaddingEnd           右
app:tabPaddingTop           上
app:tabPaddingBottom        下
app:paddingStart            整个TabLayout的左Padding
app:paddingEnd              整个TabLayout的右Padding
app:tabTextColor            Tab未被选中字体的颜色
app:tabTextAppearance       Tab中文字的样式
app:tabSelectedTextColor    Tab被选中字体的颜色
app:tabIndicatorColor       Tab指示器下标的颜色
app:tabIndicatorHeight      Tab指示器下标的高度

addTab(TabLayout.Tab tab, int position, boolean setSelected) 增加选项卡到 layout 中 
addTab(TabLayout.Tab tab, boolean setSelected)               同上 
addTab(TabLayout.Tab tab)                                    同上 
getTabAt(int index)                                          获到选项卡 
getTabCount()                                                获到选项卡的总个数 
getTabGravity()                                              获到tab的 Gravity 
getTabMode()                                                 获到tab的模式 
getTabTextColors()                                           获到tab中文本的颜色 
newTab()                                                     新建个tab 
removeAllTabs()                                              移除所有的tab 
removeTab(TabLayout.Tab tab)                                 移除指定的tab 
removeTabAt(int position)                                    移除指定位置的tab 
setCustomView(View )
setOnTabSelectedListener(TabLayout.OnTabSelectedListener onTabSelectedListener)     为每个 tab 增加选择监听器 
setScrollPosition(int position, float positionOffset, boolean updateSelectedText)   设置滚动位置 
setTabGravity(int gravity)                                   设置 Gravity 
setTabMode(int mode) 设置 Mode,有两种值:TabLayout.MODE_SCROLLABLE和TabLayout.MODE_FIXED分别表示当tab的内容超过屏幕宽度是否支持横向水平滑动,第一种支持滑动,第二种不支持,默认不支持水平滑动。 
setTabTextColors(ColorStateList textColor)                   设置tab中文本的颜色 
setTabTextColors(int normalColor, int selectedColor)         设置tab中文本的颜色 默认 选中 
setTabsFromPagerAdapter(PagerAdapter adapter)                设置 PagerAdapter 
setupWithViewPager(ViewPager viewPager)                      和ViewPager联动

如需设置默认选中项:tablayout.getTabAt(position).select();

基本使用

1.在应用的build.gradle中添加support:design支持库,版本就看自己的了

compile ‘com.android.support:design:25.3.1’

2.布局

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.materialdesignui.tablayout.TabLayoutActivity">

    <android.support.design.widget.TabLayout
        android:id="@+id/tb"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <android.support.design.widget.TabItem
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Tab1"/>

        <android.support.design.widget.TabItem
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Tab2"/>

        <android.support.design.widget.TabItem
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Tab3"/>

        <android.support.design.widget.TabItem
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Tab4"/>
    </android.support.design.widget.TabLayout>

</RelativeLayout>

也可以通过代码添加tab,这样布局也减少许多

tabLayout= (TabLayout) findViewById(R.id.tb);
tabLayout.addTab(tabLayout.newTab().setText("Tab1"));
tabLayout.addTab(tabLayout.newTab().setText("Tab2"));
tabLayout.addTab(tabLayout.newTab().setText("Tab3"));
tabLayout.addTab(tabLayout.newTab().setText("Tab4"));

效果如下:

下面修改了常用的属性

<android.support.design.widget.TabLayout
    android:id="@+id/tb"
    //tab未选中的颜色
    app:tabTextColor="@color/colorPrimary"
    //tab选中的颜色
    app:tabSelectedTextColor="@android:color/holo_orange_light"
    //tab指示器的颜色
    app:tabIndicatorColor="@android:color/holo_blue_light"
    //tab指示器的高度
    app:tabIndicatorHeight="6dp"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

效果如下:

设置tabMode属性值

<android.support.design.widget.TabLayout
    android:id="@+id/tb"
    //tab的模式
    app:tabMode="scrollable"
    //tab的最小宽度
    app:tabMinWidth="100dp"
    app:tabTextColor="@color/colorPrimary"
    app:tabSelectedTextColor="@android:color/holo_orange_light"
    app:tabIndicatorColor="@android:color/holo_blue_light"
    app:tabIndicatorHeight="6dp"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

效果如下:

设置app:tabGravity属性值

    <android.support.design.widget.TabLayout
        android:id="@+id/tb"
        //设置tab居中
        app:tabGravity="center"
        app:tabTextColor="@color/colorPrimary"
        app:tabSelectedTextColor="@android:color/holo_orange_light"
        app:tabIndicatorColor="@android:color/holo_blue_light"
        app:tabIndicatorHeight="6dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

效果如下:

上述效果使用的场景还是挺多的,tablayout也可以放在toolbar中

上面演示中字母都展示的是大写,因为默认的textAllCaps属性值为true

设置为false的话可以简单的通过app:tabTextAppearance属性来修改

    <android.support.design.widget.TabLayout
        android:id="@+id/tb"
        app:tabGravity="center"
        app:tabTextColor="@color/colorPrimary"
        //设置字体
        app:tabTextAppearance="@android:style/TextAppearance.Holo.Large"
        app:tabSelectedTextColor="@android:color/holo_orange_light"
        app:tabIndicatorColor="@android:color/holo_blue_light"
        app:tabIndicatorHeight="6dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

效果如下:

添加图片

设置tabitem

    <android.support.design.widget.TabItem
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:icon="@mipmap/ic_launcher"
        android:text="Tab1"/>

或者tabLayout.addTab(tabLayout.newTab().setText(“Tab 1”).setIcon(R.mipmap.ic_launcher));

效果如下:

如果只要图片,可以不设置text,在某些情况下使用可能会需要自定义tab的view

tablayout+viewpage

这两个是很友好的搭档,在开发中是经常会使用到的

先来个横向展示图片的效果:

这里特别强调注意的一个地方,在textAllCaps为true的话,会阻止ImageSpan渲染出来,一定要将textAllCaps设置为false

布局代码:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
          xmlns:app="http://schemas.android.com/apk/res-auto"
          android:orientation="vertical"
          android:layout_width="match_parent"
          android:layout_height="match_parent">

<android.support.design.widget.TabLayout
    android:id="@+id/tb"
    app:tabTextAppearance="@android:style/TextAppearance.Holo.Large"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"/>

<android.support.v4.view.ViewPager
    android:id="@+id/vp"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>

</LinearLayout>

TabPagerAdapter:

public class TabPagerAdapter extends PagerAdapter {

    private Context mContext;
    private static final String[] mTitles = {"tab1", "tab2", "tab3"};
    private int[] mImageIds = {R.drawable.tab_01, R.drawable.tab_02, R.drawable.tab_03};
    private final List<TextView> mList;

    public TabPagerAdapter(Context context) {
        this.mContext = context;
        mList = new ArrayList<>();

        TextView tv;
        for (int i = 0; i < 3; i++) {
            tv = new TextView(mContext);
            mList.add(tv);
        }
    }


    @Override
    public int getCount() {
        return mList.size();
    }

    @Override
    public boolean isViewFromObject(View view, Object object) {
        return view == object;
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        container.addView(mList.get(position));
        mList.get(position).setText(mTitles[position]);
        return mList.get(position);
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        container.removeView(mList.get(position));
    }

    @Override
    public CharSequence getPageTitle(int position) {
        Drawable drawable = ContextCompat.getDrawable(mContext, mImageIds[position]);
        drawable.setBounds(0, 0, drawable.getIntrinsicWidth() / 5, drawable.getIntrinsicHeight() / 5);

        ImageSpan imageSpan = new ImageSpan(drawable, ImageSpan.ALIGN_BOTTOM);
        SpannableString spannableString = new SpannableString("   " + mTitles[position]);
        spannableString.setSpan(imageSpan, 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        return spannableString;
    }
}

在getPageTitle方法中,setBounds是设置drawable的展示区域,注意大小,大小有问题的话也会展示不出来

Activity:

public class TabIconActivity extends AppCompatActivity {

    private TabLayout mTabLayout;
    private ViewPager mVp;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_tab_icon);

        mTabLayout = (TabLayout) findViewById(R.id.tb);
        mVp = (ViewPager) findViewById(R.id.vp);

        TabPagerAdapter tabPageAdapter = new TabPagerAdapter(this);
        mVp.setAdapter(tabPageAdapter);
        mTabLayout.setupWithViewPager(mVp);
    }
}

自定义视图 效果如下:

这个是通过tab的setCustomView方法设置的布局,实现了,文字+图片纵向显示

自定义布局:item_tab.xml

<?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="vertical">

    <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/tab_01"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</LinearLayout>

布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">


    <android.support.design.widget.TabLayout
        android:id="@+id/tb"
        app:tabTextAppearance="@android:style/TextAppearance.Holo.Large"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

    <android.support.v4.view.ViewPager
        android:id="@+id/vp"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</LinearLayout>

Activity:

public class TabIconVerActivity extends AppCompatActivity {

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_tab_icon_ver);

    TabLayout tabLayout = (TabLayout) findViewById(R.id.tb);
    ViewPager viewPager = (ViewPager) findViewById(R.id.vp);

    TabVerPagerAdapter tabVerPagerAdapter = new TabVerPagerAdapter(this);
    viewPager.setAdapter(tabVerPagerAdapter);
    tabLayout.setupWithViewPager(viewPager);
    for (int i = 0; i < tabLayout.getTabCount(); i++) {
        TabLayout.Tab tab = tabLayout.getTabAt(i);
        if (tab != null) {
            tab.setCustomView(tabVerPagerAdapter.getTabView(i));
        }
    }
    viewPager.setCurrentItem(1);
}

}
Adapter:

public class TabVerPagerAdapter extends PagerAdapter {


    private Context mContext;
    private static final String[] mTitles = {"tabbat1", "tabbat2", "tabbat3"};
    private int[] mImageIds = {R.drawable.tab_01, R.drawable.tab_02, R.drawable.tab_03};
    private final List<TextView> mList;

    public TabVerPagerAdapter(Context context) {
        this.mContext = context;
        mList = new ArrayList<>();

        TextView tv;
        for (int i = 0; i < 3; i++) {
            tv = new TextView(mContext);
            mList.add(tv);
        }
    }

    @Override
    public int getCount() {
        return mList.size();
    }

    @Override
    public boolean isViewFromObject(View view, Object object) {
        return view == object;
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        container.addView(mList.get(position));
        mList.get(position).setText(mTitles[position]);
        return mList.get(position);
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        container.removeView(mList.get(position));
    }

    @Override
    public CharSequence getPageTitle(int position) {
        return mTitles[position];
    }


    public View getTabView(int position){
        View view = LayoutInflater.from(mContext).inflate(R.layout.item_tab, null);
        TextView tv= (TextView) view.findViewById(R.id.txt_title);
        tv.setText(mTitles[position]);
        ImageView img = (ImageView) view.findViewById(R.id.img_title);
        img.setImageResource(mImageIds[position]);
        return view;
    }
}

主要是通过getTabView方法实现的数据加载,setCustomView实现自定义

改变指示器长度

这个主要通过反射实现的

先看效果吧

通过gif,可以看到指示器的长度改变了

代码贴出activity中的,其他没什么变化

public class TabIndicatorActivity extends AppCompatActivity{

    private TabLayout mTabLayout;
    private ViewPager mVp;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_tab_icon);


        mTabLayout = (TabLayout) findViewById(R.id.tb);
        mVp = (ViewPager) findViewById(R.id.vp);

        TabIndicatorAdapter tabPageAdapter = new TabIndicatorAdapter(this);
        mVp.setAdapter(tabPageAdapter);
        mTabLayout.setupWithViewPager(mVp);

        mTabLayout.post(new Runnable() {
            @Override
            public void run() {
                setIndicator(mTabLayout, 25, 25);
            }
        });
    }

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

在代码中view.post方法都是在view渲染完后执行的,所以有时获取的控件长宽值,或者其他需在渲染完后执行的都可使用post方法,避免出错

以上就是对TabLayout的简单的讲解,Demo已传github

Star地址:https://github.com/Kriy/AndroidMaterialDesignUI ,谢谢支持

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值