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