修改TabLayout下划线宽度,以及在Api28下遇到的问题—— tabLayout.getDeclaredField 空指针以及水波纹背景问题

在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>

 

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值