在API28之前,我们修改TabLayout下划线宽度,代码如下:
/**
* 设置tabLayout下划线的宽
*/
public static 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();
}
}
调用如下:
mTabLayout.post(() -> Tools.setIndicator(mTabLayout, 20, 20));
在API28下运行正常,当我把API改为28时,此时出问题了, 空指针异常: 错误如下:
后来我就开始找问题了:
有人说:是代码混淆导致的;在混淆里面加入这句即可。
-keep class android.support.design.widget.TabLayout{*;}
试用 无效!!
然后我就查看了API28下的TabLayout 源码,发现把原来的mTabStrip改名为slidingTabIndicator 所以才导致空指针:
修改下的代码如下:
/**
* 设置tabLayout下划线的宽
*/
public static void setIndicator(TabLayout tabs, int leftDip, int rightDip) {
Class<?> tabLayout = tabs.getClass();
Field tabStrip = null;
try {
//在API28下 调用:tabLayout.getDeclaredField("mTabStrip")
tabStrip = tabLayout.getDeclaredField("slidingTabIndicator");
} 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();
}
}
继续看源码,你会发现,API28下mTextView改名为textView了 如果你调用了:
tabLayout.getDeclaredField("mTextView"),在API28下记得改为:tabLayout.getDeclaredField("textView");
接着,你就会又出现一个问题,TabTab的点击有水波纹的背景样式, 如下:
在布局文件中我已经加上了 tabBackground 属性
app:tabBackground="@null"
但是不管用,在API28下还需要加上一句属性:
app:tabBackground="@null"
app:tabRippleColor="@null"
整体xml代码如下:
<android.support.design.widget.TabLayout
android:id="@+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="@dimen/px88"
android:background="@color/white"
app:tabBackground="@null"
app:tabRippleColor="@null"
app:tabIndicatorColor="#30A6F5"
app:tabIndicatorHeight="3dp"
app:tabMode="fixed"
app:tabSelectedTextColor="@color/text_select_color"
app:tabTextAppearance="@style/TabLayoutTextAppearance"
app:tabTextColor="#666666"
/>
好了!问题已解决,你可以接着使用了;
补:
设置下划线宽度 = tab内容宽度:
/**
* 设置tabLayout下划线的宽
*/
public static void setIndicator(TabLayout tabs) {
Class<?> tabLayout = tabs.getClass();
Field tabStrip = null;
try {
tabStrip = tabLayout.getDeclaredField("slidingTabIndicator");
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
tabStrip.setAccessible(true);
LinearLayout llTab = null;
try {
llTab = (LinearLayout) tabStrip.get(tabs);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
//因为我想要的效果是 字多宽线就多宽,所以测量mTextView的宽度
for (int i = 0, count = llTab.getChildCount(); i < count; i++) {
//获取tabView
View tabView = llTab.getChildAt(i);
//拿到tabView的mTextView属性
Field mTextViewField = null;
try {
//获取tabView的textView属性
mTextViewField = tabView.getClass().getDeclaredField("textView");
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
mTextViewField.setAccessible(true);
TextView textView = null;
try {
textView = (TextView) mTextViewField.get(tabView);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
tabView.setPadding(0, 0, 0, 0);
//获取textview宽度
int textWidth = 0;
textWidth = textView.getWidth();
if (textWidth == 0) {
textView.measure(0, 0);
textWidth = textView.getMeasuredWidth();
}
//获取tabview宽度
int tabWidth = 0;
tabWidth = tabView.getWidth();
if (tabWidth == 0) {
tabView.measure(0, 0);
tabWidth = tabView.getMeasuredWidth();
}
//设置下划线margin值
LinearLayout.LayoutParams tabViewParams = (LinearLayout.LayoutParams) tabView.getLayoutParams();
int margin = (tabWidth - textWidth) / 2;
tabViewParams.leftMargin = margin;
tabViewParams.rightMargin = margin;
tabView.setLayoutParams(tabViewParams);
}
}
上述两个方法:
在tabmode 为fiexd时,改变下划线宽度也就是Tab内容的宽度,如果设置很短,Tab内容就显示不下,会显示多行;
在tabmode 为 scrollable 时,会根据tab内容变化改变下滑线长度;
在android 28之后,TabLayout 增加了新属性app:tabIndicatorFullWidth="false"
,当为false时,下划线宽度会跟文字的长度相匹配,自动适配;
tablayout 修改字体大小:
添加属性
app:tabTextAppearance="@style/TabLayoutTextAppearance"
<android.support.design.widget.TabLayout
android:id="@+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="44dp"
android:background="@color/white"
app:tabBackground="@null"
app:tabRippleColor="@null"
app:tabIndicatorColor="#30A6F5"
app:tabIndicatorHeight="3dp"
app:tabMode="fixed"
app:tabSelectedTextColor="#f00"
app:tabTextAppearance="@style/TabLayoutTextAppearance"
app:tabTextColor="#666666"/>
对应的style代码:
<style name="TabLayoutTextAppearance" parent="TextAppearance.AppCompat.Widget.ActionBar.Title">
<item name="android:textSize">15sp</item>
</style>