API 28下使用TabLayout的坑

今天学习使用TabLayout,由于强迫症,很想把指示器的宽度设置成和文字宽度差不多,百度了很多方法,都说通过反射找到mTabStrip属性来设置,但是按照代码设置后,却一直报NoSuchFieldException异常,也就是找不到该属性,网上各种百度,说加上代码混淆,却依旧无效,最后在别人代码中看到的design版本为25,发现自己一直用的28,突然间想到可能是API的原因,百度才知道,TabLayout在API 28后不一样了,存在差异,属性由原来的mTabStrip和mTextView已经改名为slidingTabIndicator和textView。

API 28下使用TabLayout的坑_第1张图片

修改后就实现了需求,效果图如下:

API 28下使用TabLayout的坑_第2张图片

设置指示器的宽度(API 28以上,以下请使用mTabStrip和mTextView) 代码如下:

/**
     * 设置TabLayout的指示器的宽度
     * @param tabLayout TabLayout
     * @param leftMargin 左边距
     * @param rightMargin 右边距
     */
    public void setTabIndicatorWidth(final TabLayout tabLayout, final int leftMargin, final int rightMargin) {
        tabLayout.post(new Runnable() {
            @Override
            public void run() {
                try {
                    // 拿到tabLayout的slidingTabIndicator属性,API 28以前是mTabStrip
                    Field slidingTabIndicatorField = tabLayout.getClass().getDeclaredField("slidingTabIndicator");
                    slidingTabIndicatorField.setAccessible(true);
                    LinearLayout mTabStrip = (LinearLayout) slidingTabIndicatorField.get(tabLayout);
                    for (int i = 0; i < mTabStrip.getChildCount(); i++) {
                        View tabView = mTabStrip.getChildAt(i);
                        //拿到tabView的mTextView属性,API 28以前是mTextView
                        Field textViewField = tabView.getClass().getDeclaredField("textView");
                        textViewField.setAccessible(true);
                        TextView mTextView = (TextView) textViewField.get(tabView);
                        tabView.setPadding(0, 0, 0, 0);
                        //因为我想要的效果是字多宽线就多宽,所以测量mTextView的宽度
                        int width = mTextView.getWidth();
                        if (width == 0) {
                            mTextView.measure(0, 0);
                            width = mTextView.getMeasuredWidth();
                        }
                        // 设置tab左右间距,注意这里不能使用Padding,因为源码中线的宽度是根据tabView的宽度来设置的
                        LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) tabView.getLayoutParams();
                        params.width = width;
                        params.leftMargin = leftMargin;
                        params.rightMargin = rightMargin;
                        tabView.setLayoutParams(params);
                        tabView.invalidate();
                    }
                } catch (NoSuchFieldException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        });
    }

一定要注意API版本,选择对应的参数,这是我在学习TabLayout中遇到的坑,希望大家能少走点弯路。

文章参照于API 28下的TabLayout的差异

你可能感兴趣的:(API 28下使用TabLayout的坑)