需求
实现以下UI效果,指示符宽度为10dp,高度为4dp,圆角为2dp
通常的做法如下:
-
定义指示符tab_indicator.xml
<?xml version="1.0" encoding="utf-8"?> <layer-list xmlns:android="http://schemas.android.com/apk/res/android"> <item android:width="10dp" android:height="4dp" android:gravity="center"> <shape> <corners android:radius="2dp" /> </shape> </item> </layer-list>
定义TabLayout,设置 app:tabIndicator="@drawable/tab_indicator"
<com.google.android.material.tabs.TabLayout
android:id="@+id/tabLayout"
android:layout_width="wrap_content"
android:layout_height="45dp"
android:layout_gravity="center"
app:tabIndicator="@drawable/tab_indicator"
app:tabIndicatorColor="#3F51B5"
app:tabIndicatorFullWidth="false"
app:tabIndicatorHeight="4dp"
app:tabMode="scrollable"
app:tabRippleColor="@android:color/transparent"
app:tabSelectedTextColor="#333333"
app:tabTextColor="#999999" />
在Android 6.0及以上系统的展示效果如下:
在Android 5.1的机器上展示效果如下:
在Android 5.1的机器上指示符的宽度和文本的宽度一样长,而不是我们想要的10dp
问题排查
检查了一下代码,发现xml文件中layer-list节点下android:width/height属性在Android 6.0以下系统无效,当我们把光标放在tab_indicator.xml布局文件里会有这样的提示: Attribute width is only used in API level 23 and higher (current min is 21)
解决方案
在代码中动态设置指示符宽度,添加一个TabLayout的扩展方法,如下:
/**
* 设置指示符固定宽度
*/
fun TabLayout.setSelectedTabIndicatorFixWidth(width: Float) {
setSelectedTabIndicator(object : DrawableWrapper(tabSelectedIndicator) {
override fun setBounds(left: Int, top: Int, right: Int, bottom: Int) {
var realLeft = left
var realRight = right
if ((right - left).toFloat() != width) {
val center = left + (right - left).toFloat() / 2
realLeft = (center - width / 2).toInt()
realRight = (center + width / 2).toInt()
}
super.setBounds(realLeft, top, realRight, bottom)
}
})
}
使用
tab_indicator.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<corners android:radius="2dp" />
</shape>
布局文件
<com.google.android.material.tabs.TabLayout
android:id="@+id/tabLayout"
android:layout_width="wrap_content"
android:layout_height="45dp"
android:layout_gravity="center"
app:tabIndicator="@drawable/tab_indicator"
app:tabIndicatorColor="#3F51B5"
app:tabIndicatorFullWidth="false"
app:tabIndicatorHeight="4dp"
app:tabMode="scrollable"
app:tabRippleColor="@android:color/transparent"
app:tabSelectedTextColor="#333333"
app:tabTextColor="#999999" />
tabLayout.setSelectedTabIndicatorFixWidth(dp2px(10f))
最终效果
- Android 5.0 & 5.1
- Android 6.0+