首页

TabLayout 全面总结

seo达人

如果您想订阅本博客内容,每天自动发到您的邮箱中, 请点这里

一、简介

TabLayout提供了一个水平布局用于展示tabs,继承自HorizontalScrollView。一般与Viewpager结合使用实现页面和标签联动的效果,是时下APP中非常常用的一个控件



二、基本用法

  1. 添加design依赖

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

    1
  2. xml引用
  3. xml中添加tab

    <android.support.design.widget.TabLayout

        android:id="@+id/tab_layout"

        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>

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21
  4. 代码中添加tab

    <android.support.design.widget.TabLayout

        android:id="@+id/tab_layout"

        android:layout_width="match_parent"

        android:layout_height="wrap_content">

    </android.support.design.widget.TabLayout>

    1

    2

    3

    4

    5

    // tablayout,Tab是TabLayout的内部类,且Tab的构造方法是包访问权限

    TabLayout tabLayout = (TabLayout) findViewById(R.id.tab_layout);

    tabLayout.addTab(tabLayout.newTab().setText("Tab1"));

    tabLayout.addTab(tabLayout.newTab().setText("Tab2"));

    tabLayout.addTab(tabLayout.newTab().setText("Tab3"));

    tabLayout.addTab(tabLayout.newTab().setText("Tab4"));

    1

    2

    3

    4

    5

    6





    三、属性详解

    <declare-styleable name="TabLayout">

        <!--指示器颜色-->

        <attr name="tabIndicatorColor" format="color"/>

        <!--指示器高度-->

        <attr name="tabIndicatorHeight" format="dimension"/>

        <!--tabs距TabLayout开始位置的偏移量,但app:tabMode="scrollable"才生效-->

        <attr name="tabContentStart" format="dimension"/>

        <!--仅是Tab背景,设置TabLayout背景用android:background-->

        <attr name="tabBackground" format="reference"/>

        <!--默认fixed,所有Tab只能在屏幕内显示,超出会被挤压;scrollable,tab数量多会超出屏幕,可滑动-->

        <attr name="tabMode">

            <enum name="scrollable" value="0"/>

            <enum name="fixed" value="1"/>

        </attr>

        <!--默认fill,tab填满TabLayout,但tabMode=“fixed”才生效;center,tabs位于TabLayout的中间-->

        <attr name="tabGravity">

            <enum name="fill" value="0"/>

            <enum name="center" value="1"/>

        </attr>

        <!--Tab的最小宽度-->

        <attr name="tabMinWidth" format="dimension"/>

        <!--Tab的最大宽度-->

        <attr name="tabMaxWidth" format="dimension"/>

        <!--Tab文本设置样式-->

        <attr name="tabTextAppearance" format="reference"/>

        <!--Tab未选中字体颜色-->

        <attr name="tabTextColor" format="color"/>

        <!--Tab选中字体颜色-->

        <attr name="tabSelectedTextColor" format="color"/>

        <!--Tab内填充相关-->

        <attr name="tabPaddingStart" format="dimension"/>

        <attr name="tabPaddingTop" format="dimension"/>

        <attr name="tabPaddingEnd" format="dimension"/>

        <attr name="tabPaddingBottom" format="dimension"/>

        <attr name="tabPadding" format="dimension"/>

    </declare-styleable>

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    30

    31

    32

    33

    34

    35

    36

    使用示例



     <android.support.design.widget.TabLayout

        android:id="@+id/tab_layout"

        android:layout_width="match_parent"

        android:layout_height="wrap_content"

        app:tabIndicatorColor="@color/colorPrimaryDark"

        app:tabIndicatorHeight="2dp"

        app:tabContentStart="50dp"

        app:tabBackground="@color/colorAccent"

        app:tabMode="scrollable"

        app:tabGravity="fill"

        app:tabTextAppearance="@style/MyTabTextAppearance"

        app:tabTextColor="@android:color/black"

        app:tabSelectedTextColor="@android:color/white"/>

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    <style name="MyTabTextAppearance" parent="TextAppearance.Design.Tab">

        <item name="textAllCaps">false</item>

        <item name="android:textSize">18sp</item>

    </style>

    1

    2

    3

    4





    四、图文混排,Tab中添加图片
  5. 通过SpannableString设置图片

    @NonNull

    private SpannableString setImageSpan(String string,int drawableId) {

        SpannableString ss = new SpannableString("  "+string);

        Drawable drawable = ContextCompat.getDrawable(this, drawableId);

        drawable.setBounds(0,0,drawable.getIntrinsicWidth(),drawable.getIntrinsicHeight());

        ImageSpan imageSpan = new ImageSpan(drawable);

        ss.setSpan(imageSpan,0,1, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);

        return ss;

    }

    1

    2

    3

    4

    5

    6

    7

    8

    9

    TabLayout tabLayout = (TabLayout) findViewById(R.id.tab_layout);

    tabLayout.addTab(tabLayout.newTab().setText(setImageSpan("Tab1",R.drawable.ic_home)));

    tabLayout.addTab(tabLayout.newTab().setText(setImageSpan("Tab2",R.drawable.ic_info)));

    ……

    1

    2

    3

    4





    我们会发现个问题,通过ImageSpan设置的图片和文字没有对齐,先百度到一个可用方法解决:重写ImageSpan的draw()方法



    package com.strivestay.tablayoutdemo;



    import android.graphics.Bitmap;

    import android.graphics.Canvas;

    import android.graphics.Paint;

    import android.graphics.drawable.Drawable;

    import android.support.annotation.NonNull;

    import android.text.style.ImageSpan;



    public class CenterImageSpan extends ImageSpan {

        public CenterImageSpan(Drawable drawable) {

            super(drawable);



        }



        public CenterImageSpan(Bitmap b) {

            super(b);

        }



        @Override

        public void draw(@NonNull Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom,

                         @NonNull Paint paint) {



            Drawable b = getDrawable();

            Paint.FontMetricsInt fm = paint.getFontMetricsInt();

            int transY = (y + fm.descent + y + fm.ascent) / 2 - b.getBounds().bottom / 2;//计算y方向的位移

            canvas.save();

            canvas.translate(x, transY);//绘制图片位移一段距离

            b.draw(canvas);

            canvas.restore();

        }

    }

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    30

    31

    32

    33

    将上面的ImageSpan替换为现在的CenterImageSpan,即可实现图文混排时对齐






  6. 通过Tab.setCustomView()设置图片
  7. 自定义view布局

    <?xml version="1.0" encoding="utf-8"?>

    <LinearLayout

        xmlns:android="http://schemas.android.com/apk/res/android"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:orientation="vertical"

        android:gravity="center">

        <ImageView

            android:id="@+id/iv"

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:src="@drawable/ic_home"/>

        <TextView

            android:id="@+id/tv"

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:layout_margin="2dp"

            android:textSize="16sp"

            android:text="首页"/>

    </LinearLayout>

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20
  8. 代码设置

     TabLayout tabLayout = (TabLayout) findViewById(R.id.tab_layout);

    tabLayout.addTab(tabLayout.newTab().setCustomView(setCustomView(R.drawable.ic_home,"首页")));

    tabLayout.addTab(tabLayout.newTab().setCustomView(setCustomView(R.drawable.ic_info,"资讯")));

    tabLayout.addTab(tabLayout.newTab().setCustomView(setCustomView(R.drawable.ic_live,"直播")));

    tabLayout.addTab(tabLayout.newTab().setCustomView(setCustomView(R.drawable.ic_me,"我")));

    1

    2

    3

    4

    5

     private View setCustomView(int drawableId,String tabText) {

        View view = View.inflate(this, R.layout.item_tab, null);

        ImageView iv = (ImageView) view.findViewById(R.id.iv);

        TextView tv = (TextView) view.findViewById(R.id.tv);

        iv.setImageResource(drawableId);

        tv.setText(tabText);

        return view;

    }

    1

    2

    3

    4

    5

    6

    7

    8





    五、TabLayout与Viewpager联动
  9. xml设置TabLayout和Viewpager

    第一种:TabLayout放置在Viewpager的上方,放在AppbarLayout中会有阴影效果



    <?xml version="1.0" encoding="utf-8"?>

    <android.support.design.widget.CoordinatorLayout

        xmlns:android="http://schemas.android.com/apk/res/android"

        xmlns:app="http://schemas.android.com/apk/res-auto"

        xmlns:tools="http://schemas.android.com/tools"

        android:id="@+id/main_content"

        android:layout_width="match_parent"

        android:layout_height="match_parent"

        android:fitsSystemWindows="true"

        tools:context="com.strivestay.tablayoutdemo.MainActivity">



        <android.support.design.widget.AppBarLayout

            android:id="@+id/appbar"

            android:layout_width="match_parent"

            android:layout_height="wrap_content"

            android:paddingTop="@dimen/appbar_padding_top"

            android:theme="@style/AppTheme.AppBarOverlay">



            <android.support.v7.widget.Toolbar

                android:id="@+id/toolbar"

                android:layout_width="match_parent"

                android:layout_height="?attr/actionBarSize"

                android:background="?attr/colorPrimary"

                app:layout_scrollFlags="scroll|enterAlways"

                app:popupTheme="@style/AppTheme.PopupOverlay">



            </android.support.v7.widget.Toolbar>



            <android.support.design.widget.TabLayout

                android:id="@+id/tab_layout"

                android:layout_width="match_parent"

                android:layout_height="wrap_content"

                app:tabIndicatorColor="@color/colorAccent"

                app:tabIndicatorHeight="2dp"

                app:tabBackground="@android:color/white"

                app:tabTextAppearance="@style/MyTabTextAppearance"

                app:tabTextColor="@android:color/black"

                app:tabSelectedTextColor="@android:color/holo_blue_light">

            </android.support.design.widget.TabLayout>



        </android.support.design.widget.AppBarLayout>



        <android.support.v4.view.ViewPager

            android:id="@+id/container"

            android:layout_width="match_parent"

            android:layout_height="match_parent"

            app:layout_behavior="@string/appbar_scrolling_view_behavior"/>



        <android.support.design.widget.FloatingActionButton

            android:id="@+id/fab"

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:layout_gravity="end|bottom"

            android:layout_margin="@dimen/fab_margin"

            app:srcCompat="@android:drawable/ic_dialog_email"/>



    </android.support.design.widget.CoordinatorLayout>

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    30

    31

    32

    33

    34

    35

    36

    37

    38

    39

    40

    41

    42

    43

    44

    45

    46

    47

    48

    49

    50

    51

    52

    53

    54

    55

    56

    57

    58





    第二种:TabLayout直接放在Viewpager,无阴影



    <android.support.v4.view.ViewPager

        android:id="@+id/container"

        android:layout_width="match_parent"

        android:layout_height="match_parent"

        app:layout_behavior="@string/appbar_scrolling_view_behavior">

        <android.support.design.widget.TabLayout

            android:id="@+id/tab_layout"

            android:layout_width="match_parent"

            android:layout_height="wrap_content"

            app:tabIndicatorColor="@color/colorAccent"

            app:tabIndicatorHeight="2dp"

            app:tabBackground="@android:color/white"

            app:tabTextAppearance="@style/MyTabTextAppearance"

            app:tabTextColor="@android:color/black"

            app:tabSelectedTextColor="@android:color/holo_blue_light">

        </android.support.design.widget.TabLayout>

    </android.support.v4.view.ViewPager>

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17




  10. 为Viewpager创建适配器

    /

      fragment

     
    /

    public static class PlaceholderFragment extends Fragment {

        private static final String ARG_SECTION = "section";



        public PlaceholderFragment() {

        }



        public static PlaceholderFragment newInstance(String section) {

            PlaceholderFragment fragment = new PlaceholderFragment();

            Bundle args = new Bundle();

            args.putString(ARG_SECTION, section);

            fragment.setArguments(args);

            return fragment;

        }



        @Override

        public View onCreateView(LayoutInflater inflater, ViewGroup container,

                                 Bundle savedInstanceState) {

            View rootView = inflater.inflate(R.layout.fragment_main, container, false);

            TextView textView = (TextView) rootView.findViewById(R.id.section_label);

            textView.setText(getArguments().getString(ARG_SECTION));

            return rootView;

        }

    }



    /


      pagerAdapter

     
    /

    public class SectionsPagerAdapter extends FragmentPagerAdapter {

        String[] tabs = {"首页","资讯","直播","我"};



        public SectionsPagerAdapter(FragmentManager fm) {

            super(fm);

        }



        @Override

        public Fragment getItem(int position) {

            return PlaceholderFragment.newInstance(tabs[position]);

        }



        @Override

        public int getCount() {

            return tabs.length;

        }



        @Override

        public CharSequence getPageTitle(int position) {

            return tabs[position];

        }

    }

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    30

    31

    32

    33

    34

    35

    36

    37

    38

    39

    40

    41

    42

    43

    44

    45

    46

    47

    48

    49

    50

    51

    52

    主要是重写getPageTitle()方法


  11. 代码设置 TabLayout和Viewpager绑定

     // tablayout

    TabLayout tabLayout = (TabLayout) findViewById(R.id.tab_layout);



    // vp

    mViewPager = (ViewPager) findViewById(R.id.container);

    mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());

    mViewPager.setAdapter(mSectionsPagerAdapter);



    // 绑定,要在viewpager设置完数据后,调用此方法,否则不显示 tabs文本

    tabLayout.setupWithViewPager(mViewPager);

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    调用setupWithViewPager()方法,则使用TabLayout.addtab()方法无效,TabLayout会清除之前添加的所有tabs,并将根据Viewpager的页数添加Tab,Tab标题为对应页通过getPageTitle()返回的文本






  12. 图文混排
  13. 同上,使用SpannableString

    修改Adapter如下:



    /*

     
    pagerAdapter

     */

    public class SectionsPagerAdapter extends FragmentPagerAdapter {



        String[] tabs = {"首页","资讯","直播","我"};

        int[] imgs = {R.drawable.ic_home,R.drawable.ic_info,R.drawable.ic_live,R.drawable.ic_me};



        public SectionsPagerAdapter(FragmentManager fm) {

            super(fm);

        }



        @Override

        public Fragment getItem(int position) {

            return PlaceholderFragment.newInstance(tabs[position]);

        }



        @Override

        public int getCount() {

            return tabs.length;

        }



        @Override

        public CharSequence getPageTitle(int position) {

    //            return tabs[position];

            return setImageSpan(tabs[position],imgs[position]);

        }

    }

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    setImageSpan()方法同上






  14. 同上,使用Tab.setCustomView()

    修改pagerAdapter如下:



    /

      pagerAdapter

     
    /

    public class SectionsPagerAdapter extends FragmentPagerAdapter {



        String[] tabs = {"首页","资讯","直播","我"};

        int[] imgs = {R.drawable.ic_home,R.drawable.ic_info,R.drawable.ic_live,R.drawable.ic_me};



        public SectionsPagerAdapter(FragmentManager fm) {

            super(fm);

        }



        @Override

        public Fragment getItem(int position) {

            return PlaceholderFragment.newInstance(tabs[position]);

        }



        @Override

        public int getCount() {

            return tabs.length;

        }



        @Override

        public CharSequence getPageTitle(int position) {

    //            return tabs[position];

    //            return setImageSpan(tabs[position],imgs[position]);

            return null;

        }



        /


          设置自定义view

         
    @param position

          @return

         
    /

        public View setCustomView(int position) {

            View view = View.inflate(getApplicationContext(), R.layout.item_tab, null);

            ImageView iv = (ImageView) view.findViewById(R.id.iv);

            TextView tv = (TextView) view.findViewById(R.id.tv);

            iv.setImageResource(imgs[position]);

            tv.setText(tabs[position]);

            return view;

        }

    }

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    30

    31

    32

    33

    34

    35

    36

    37

    38

    39

    40

    41

    42

    43

    代码修改如下:



    …………

    // 绑定,要在viewpager设置完数据后,调用此方法,否则不显示 tabs文本

    tabLayout.setupWithViewPager(mViewPager);



    // 为绑定viewpager后的TabLayout的tabs设置自定义view

    for (int i = 0; i < mSectionsPagerAdapter.getCount(); i++) {

        tabLayout.getTabAt(i).setCustomView(mSectionsPagerAdapter.setCustomView(i));

    }

    1

    2

    3

    4

    5

    6

    7

    8

    发现问题:我使用的仍然是上面的item_tab,但是只显示图片,不显示文字如下







    翻了翻源码,也没发现有对Tab的标题有特别的设置;后来,就感觉是不是颜色问题,给item_tab中的textview加上属性android:textColor="@android:color/black",就显示出来了







    六、FlycoTabLayout

    这是一个不错的TabLayout开源项目,效果挺好,可以了解一下。





    蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务

日历

链接

blogger

蓝蓝 http://www.lanlanwork.com

存档