Material Design 控件知识梳理(8) - TabLayout

Material Design 控件知识梳理(1) - Android Design Support Library 是什么
Material Design 控件知识梳理(2) - AppBarLayout & CollapsingToolbarLayout
Material Design 控件知识梳理(3) - BottomSheet && BottomSheetDialog && BottomSheetDialogFragment
Material Design 控件知识梳理(4) - FloatingActionButton
Material Design 控件知识梳理(5) - DrawerLayout && NavigationView
Material Design 控件知识梳理(6) - Snackbar
Material Design 控件知识梳理(7) - BottomNavigationBar
Material Design 控件知识梳理(8) - TabLayout
Material Design 控件知识梳理(9) - TextInputLayout

一、概述

前面我们介绍了BottomNavigationBarTabLayout和它的作用类似,都是方便用户进行页面之间的切换。

二、TabLayout的基本用法

下面,我们先演示一遍TabLayout的基本用法
第一步:引入依赖:

compile 'com.android.support:design:25.3.1'

第二步:定义布局,这里使用了最常用的TabLayout+ViewPager的结构:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.demo.lizejun.repotransition.TabLayoutActivity">
    <android.support.design.widget.TabLayout
        android:id="@+id/tab_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:tabMode="scrollable"
        app:tabGravity="center"/>
    <android.support.v4.view.ViewPager
        android:id="@+id/vp_content"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</LinearLayout>

第三步:定义ViewPagerAdapter,这里需要重写getPageTitle方法,它就对应的是TabLayout当中的文案:

public class ViewPagerAdapter extends PagerAdapter {

    private List<String> mTitles;

    public ViewPagerAdapter(List<String> title) {
        mTitles = title;
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        ViewGroup itemView = (ViewGroup) LayoutInflater.from(container.getContext()).inflate(R.layout.item_view_pager, container, false);
        container.addView(itemView);
        TextView tv = (TextView) itemView.findViewById(R.id.tv_title);
        tv.setText(mTitles.get(position));
        return itemView;
    }

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

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

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

    @Override
    public CharSequence getPageTitle(int position) {
        return mTitles.get(position);
    }
}

第四步:给ViewPager设置数据,并把ViewPagerTabLayout关联起来:

public class TabLayoutActivity extends AppCompatActivity {

    private static final String[] TITLE_SHORT = new String[] {
            "深圳","南京","内蒙古"
    };

    private static final String[] TITLE_LONG = new String[] {
            "深圳","南京","内蒙古呼和浩特","广西壮族自治区","上海","北京","天津"
    };

    private ViewPager mViewPager;
    private TabLayout mTabLayout;
    private ViewPagerAdapter mViewPagerAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_tab_layout);
        initViewPager();
        initTabLayout();
    }

    private void initViewPager() {
        mViewPager = (ViewPager) findViewById(R.id.vp_content);
        List<String> titles = new ArrayList<>();
        Collections.addAll(titles, TITLE_LONG);
        mViewPagerAdapter = new ViewPagerAdapter(titles);
        mViewPager.setAdapter(mViewPagerAdapter);
    }

    private void initTabLayout() {
        mTabLayout = (TabLayout) findViewById(R.id.tab_layout);
        mTabLayout.setupWithViewPager(mViewPager);
    }

}

最终的效果为:


三、TabLayout相关设置

3.1 TabItem的外观设置

对于每个TabItem的外观,TabLayout我们比较常用的属性有:

  • 未选中TabItem的文本颜色:app:tabTextColor
  • 选中TabItem的文本颜色app:tabSelectedTextColor
  • 底部滑动条的颜色:app:tabIndicatorColor
  • 底部滑动条的高度:app:tabIndicatorHeight
  • TabItem的背景:app:tabBackground

我们在第二节的基础上进行修改:

<android.support.design.widget.TabLayout
        android:id="@+id/tab_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:tabMode="scrollable"
        app:tabGravity="center"
        app:tabTextColor="@android:color/darker_gray"
        app:tabSelectedTextColor="@android:color/holo_orange_dark"
        app:tabIndicatorColor="@android:color/holo_orange_dark"
        app:tabIndicatorHeight="2dp"
        app:tabBackground="@android:color/transparent" />

最终展现的效果为:


3.2 TabItem的宽高相关设置

有两个关于宽度的属性比较重要:tabMinWidthtabMaxWidth,它允许我们这是每个TabItem的最小和最大宽度。
此外,我们还可以设置TabItem四个维度的Padding

3.3 tabModetabGravity

上面只是决定了单个TabItem的外观,而TabItemTabLayout当中的摆放规则需要由这两个属性来决定,它们可选的值分别为:

  • tabModefixed或者scrollable
  • tabGravityfill或者center

这两个属性分别通过:app:tabModeapp:tabGravity来设置,下面,我们就来解释这几个值的含义。

3.3.1 tabMode=fixed

在这种模式下,每个TabItem的宽度都是相等的,并且所有的TabItem加起来的宽度不会大于TabLayout的宽度,最终展现的结果还需要依赖于tabGravity属性:

  • tabGravity=fill
    要求所有TabItem加起来的宽度等于TabLayout的宽度,也就是下面的效果
  • tabGravity=center
    不要求TabItem加起来的宽度等于TabLayout的宽度,会根据每个TabItem的属性,计算出TabItem的宽度,然后取它们中的最大值乘上TabItem的个数,当这一数值小于TabLayout的宽度时,会将每个TabItem的宽度设置为这个最大值,并将它们放置在整个TabLayout的中间,而如果这一数值大于TabLayout的宽度,那么会将它们在TabLayout中均匀排列。

3.3.2 tabMode=scrollable

tabMode=fixed模式下,TabItem的位置是固定的,并且它们加起来的宽度不会大于TabLayout的宽度,而在scrollable模式下则没有这一限制,只需要计算好每个TabItem的宽度,然后把它们排列在TabLayout中就好了,可以通过拖动的方式查看更多的TabItem,并且当tabMode=scrollable时,tabGravity其实并没有作用,下面是tabMode=scrollable的事例:


在这种模式下,每个TabItem的宽度默认情况下是根据文字的宽度计算出来的,如果我们希望进行相应的限制,那么可以修改tabMinWidth或者tabMaxWidth属性。

3.4 设置监听

mTabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {

            @Override
            public void onTabSelected(TabLayout.Tab tab) {
                Log.d("onTabSelected", "position=" + tab.getPosition());
            }

            @Override
            public void onTabUnselected(TabLayout.Tab tab) {
                Log.d("onTabUnselected", "position=" + tab.getPosition());

            }

            @Override
            public void onTabReselected(TabLayout.Tab tab) {
                Log.d("onTabReselected", "position=" + tab.getPosition());

            }
});
  • onTabSelected,某个TabItem从未选中状态变为选中状态时回调
  • onTabUnselected,某个TabItem从选中变为未选中时回调
  • onTabReselected,某个TabItem已经处于选中状态,但是它又被再次点击了,那么回调这个函数。

四、TabLayout + ViewPager

使用TabLayout时,一般都是采用ViewPager来管理多个子界面,而TabLayout也十分贴心地提供了方法让它和ViewPager的滚动关联起来,当点击TabLayout中的Item时,会切换到ViewPager对应的界面,而如果滑动了ViewPager,那么TabLayout也会切换到对应的TabItem
我们所需要的只是下面这句设置:

mTabLayout.setupWithViewPager(mViewPager);

为了能让TabLayout知道TabItem的标题,需要重写ViewPager所对应的PagerAdaptergetPageTitle的方法:

@Override
public CharSequence getPageTitle(int position) {
    return mTitles.get(position);
}

虽然TabLayout并没有提供切换到某个具体位置TabItem的方法,但是其实这一过程这完全可以通过mViewPager.setCurrentItem(int item)来实现。


更多文章,欢迎访问我的 Android 知识梳理系列:

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 151,511评论 1 330
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 64,495评论 1 273
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 101,595评论 0 225
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 42,558评论 0 190
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 50,715评论 3 270
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 39,672评论 1 192
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,112评论 2 291
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 29,837评论 0 181
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,417评论 0 228
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 29,928评论 2 232
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,316评论 1 242
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 27,773评论 2 234
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,253评论 3 220
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,827评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,440评论 0 180
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 34,523评论 2 249
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 34,583评论 2 249

推荐阅读更多精彩内容