注:使用新的属性需要设置
implementation 'com.android.support:design:28.0.0'
在布局里加入 TabLayout,默认是下划线的样式,可以使用 tabIndicatorGravity
属性设置为:bottom
(默认值,可以不用设置,指示器显示在底部)、 top
(指示器显示在顶部)、center
(指示器显示在中间)、stretch
(指示器高度拉伸铺满 item)。
<android.support.design.widget.TabLayout
android:id="@+id/tl"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabIndicatorColor="@color/colorPrimary"
app:tabIndicatorFullWidth="true"
<!-- 设置 Indicator 高度 -->
app:tabIndicatorHeight="2dp"
app:tabMode="scrollable" />
1. "app:tabIndicatorFullWidth" 属性
注意 app:tabIndicatorFullWidth="true"
属性,设为 true,是 Indicator 充满 item 的宽度:
设为 false 是 Indicator 保持和 item 的内容宽度一致:
2. 给 Indicator 设置边距
网上的做法一般是通过反射来设置 Indicator 的宽度,可以参见博客:
关于Android改变TabLayout 下划线(Indicator)宽度实践总结
不过我觉得可以使用 layer-list
来实现。
在 drawable
文件夹下新建一个 indicator.xml
文件:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
<!-- 设置左边距 -->
android:left="15dp"
<!-- 设置右边距 -->
android:right="15dp">
<!-- 注:这里需要一个空的 <shape /> 标签,否则会报错 -->
<shape />
</item>
</layer-list>
需要注意的是在 shape 里设置颜色是无效的,需要在布局文件里设置 Indicator 颜色。
在 TabLayout
布局里添加 Indicator 的样式:
<android.support.design.widget.TabLayout
android:id="@+id/tl"
android:layout_width="match_parent"
android:layout_height="wrap_content"
<!-- 设置 Indicator 高度 -->
app:tabIndicatorHeight="2dp"
<!-- 设置 Indicator 颜色 -->
app:tabIndicatorColor="@color/colorPrimary"
<!-- 设置 Indicator 的样式 -->
app:tabIndicator="@drawable/indicator"
app:tabMode="scrollable" />
3. 给 Indicator 设置圆角
如果不需要边距,只需要圆角,可以配合 app:tabIndicatorFullWidth
属性,使用 shape
设置 app:tabIndicator
来实现圆角即可,无需使用 layer-list
,代码就不用贴了吧~
这里为了使效果看得明显一点,把 Indicator 的高度设置为 5dp。
给 Indicator 添加了 5dp 的圆角:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:left="15dp"
android:right="15dp">
<shape>
<corners android:radius="5dp" />
</shape>
</item>
</layer-list>
4. 给 Indicator 设置宽高
4.1 在 <shape>
的 <size>
标签里设置宽高:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 若不设置 gravity,则 Indicator 宽度会填满整个 item -->
<item android:gravity="center_horizontal">
<shape>
<corners android:radius="5dp" />
<size
android:width="20dp"
android:height="5dp" />
</shape>
</item>
</layer-list>
4.2 在 API 23 以上,支持直接在 layer-list
里给 <item>
标签设置宽度和高度:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:width="20dp"
android:height="5dp"
<!-- 若不设置 gravity 则默认是居左显示,需要设置为水平居中显示 -->
android:gravity="center_horizontal">
<shape>
<corners android:radius="5dp" />
</shape>
</item>
</layer-list>
5. tabIndicator 属性源码分析
TabLayout
的 tabIndicator
属性里设置的 layer-list
不支持设置颜色。
我们查看一下 TabLayout
的源码,搜索 TabLayout_tabIndicator
:
this.setSelectedTabIndicator(MaterialResources.getDrawable(context, a, styleable.TabLayout_tabIndicator));
setSelectedTabIndicator()
方法:
搜索一下使用
tabSelectedIndicator
的地方,在 SlidingTabIndicator
类里的 draw()
方法里:第 1 处
tabSelectedIndicator
再看一下
selectedIndicatorHeight
是什么:selectedIndicatorHeight
是在布局里给 TabLayout
设置的 tabIndicatorHeight
属性。
可见如果我们在布局里给 TabLayout
设置了 tabIndicatorHeight
属性,则 Indicator 高度优先取 tabIndicatorHeight
设置的高度;否则才会取咱们自定义的 drawable
里的高度。
继续,第 2 处 tabSelectedIndicator
黄色方框里可以发现,为什么之前在
drawable
里设置的颜色无效了,因为使用的是 TabLayout_tabIndicatorColor
属性里设置的颜色,所以 <stroke>
也无效,只保留了整体的形状样式。
6. 自定义复杂的 Indicator 样式
如果需要复杂一点的样式,比如 <stroke>
。
先写一个 tab 被选中时的样式 indicator.xml
:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
<!-- 设置边距 -->
android:bottom="8dp"
android:left="8dp"
android:right="8dp"
android:top="8dp">
<shape>
<!-- 设置圆角 -->
<corners android:radius="5dp" />
<!-- 设置边框 -->
<stroke
android:width="1dp"
android:color="@color/colorAccent" />
</shape>
</item>
</layer-list>
还需要一个 selector.xml
:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/indicator" android:state_selected="true" />
</selector>
接下来,我们要设置的是 tabBackground
,也就是 tab 标签的背景,而不再是tabIndicator
,所以要把 Indicator 的高度设为 0 ,不使用 tab 原生的 Indicator。
这里还要注意一下 tabRippleColor
属性,是设置点击 tab 标签时的波纹颜色,不设置的时候,默认是灰色的,文章前面的截图里有显示效果。如果想去掉这个效果,设置颜色为透明即可。
<android.support.design.widget.TabLayout
android:id="@+id/tl"
android:layout_width="match_parent"
android:layout_height="wrap_content"
<!-- 使用我们自定义的点击样式 -->
app:tabBackground="@drawable/selector"
<!-- tabIndicator 高度设为 0 -->
app:tabIndicatorHeight="0dp"
app:tabMode="scrollable"
<!-- 设置点击时的波纹颜色为透明 -->
app:tabRippleColor="@android:color/transparent" />
想实现更复杂的效果,可以使用 MagicIndicator
附上一个效果图,感觉还是很酷炫的: