TabLayout用過的小伙伴都知道屋讶,在默認的情況下它的下劃線指示器長度是與你的標題長度對應(yīng)的,像下方圖示一樣:
為什么會這樣呢爆班?查看源碼你就會發(fā)現(xiàn):這個下劃線指示器的寬度使用的是 所有tabView中的最大寬度(循環(huán)讀取所有tabView矩乐,獲取最大寬度),而且TabLayout本身并沒有提供設(shè)置這個指示器寬度的方法傀蚌。而現(xiàn)在問題來了,如果需要修改這個寬度該怎么樣做呢?
接下來介紹兩種方法:
第一種:僅限于所有的tabView的text字數(shù)都是相同字數(shù)柳譬,比如所有的圖中所有的tab字數(shù)都是2個
直接上代碼喳张,具體解釋請看注釋
```
/**
* 通過反射機制 修改TabLayout 的下劃線長度
*/
public 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();
? ? }
//設(shè)置模式
? ? tabStrip.setAccessible(true);
? ? //獲得tabview
? ? LinearLayout llTab =null;
? ? try {
llTab = (LinearLayout) tabStrip.get(tabs);
? ? }catch (IllegalAccessException e) {
? ? ?e.printStackTrace();
? ? }
//設(shè)置tabView的padding為0,并且設(shè)置了margin
? ? 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();
? ? }
}
```
然后使用的話,直接調(diào)用方法即可.必須要在Tablayout渲染出來后調(diào)用,我們可以選擇view.post()方法來實現(xiàn)美澳,比如:
```
//設(shè)置下劃線長度
tabLayout.post(new Runnable() {
@Override
? ? public void run() {
? ? ? setIndicator(tabLayout,60,60);
? ? }
});
```
到此這種方法就搞定啦销部,這個時候再運行程序你就會看到效果:
這種思路是設(shè)置tabView的padding為0,并且設(shè)置了margin制跟,其實這種方案是錯誤的舅桩,他并沒有真正的去修改指示器寬度,而且它影響了tabview之間的間距雨膨,如果tabview多的話會被擠出去擂涛,它僅限于字數(shù)一樣的原因是:如果字數(shù)不一樣,tablayout會強制設(shè)置tabView的寬度為 幾個tabView中最寬的寬度,比如4個字的tabview和2個字的tabview的組合聊记,兩個tabview的寬度j將會強制為4個字的tabview的寬度撒妈。
因此這種解決方法適用性很差,像這種tabview個數(shù)不多的情況倒是可以使用這種排监。接下來我們看看第二種方法:
第二種:在第一種基礎(chǔ)上改進狰右,適應(yīng)性相對好很多
首先我們看默認的效果是什么樣的:
剛開始我們就提到了,源碼中 線的寬度是根據(jù) tabView的寬度來設(shè)置的舆床,那我們可以根據(jù)這個來入手棋蚌,通過反射拿到SlidingTabStrip,再通過遍歷拿到tabview挨队,繼續(xù)通過反射拿到textview谷暮,然后設(shè)置Tabview的寬度為textview的寬度,這樣就改變了指示器的寬度:看代碼
```
public void setIndicatorWidth(final TabLayout tabLayout){
//從源碼得知 線的寬度是根據(jù) tabView的寬度來設(shè)置的
? ? tabLayout.post(new Runnable() {
@Override
? ? ? ? public void run() {
try {
//拿到tabLayout的mTabStrip屬性
? ? ? ? ? ? ? ? LinearLayout mTabStrip = (LinearLayout)tabLayout.getChildAt(0);
? ? ? ? ? ? ? ? //將dp轉(zhuǎn)換成px
? ? ? ? ? ? ? ? int dp10 = MiscUtil.dipToPx(tabLayout.getContext(), 10);
? ? ? ? ? ? ? ? for (int i =0; i < mTabStrip.getChildCount(); i++) {
View tabView = mTabStrip.getChildAt(i);
? ? ? ? ? ? ? ? ? ? //拿到tabView的mTextView屬性? tab的字數(shù)不固定一定用反射取mTextView
? ? ? ? ? ? ? ? ? ? Field mTextViewField = tabView.getClass().getDeclaredField("mTextView");
? ? ? ? ? ? ? ? ? ? mTextViewField.setAccessible(true);
? ? ? ? ? ? ? ? ? ? TextView mTextView = (TextView) mTextViewField.get(tabView);
? ? ? ? ? ? ? ? ? ? tabView.setPadding(0, 0, 0, 0);
? ? ? ? ? ? ? ? ? ? //想要的效果是? 字多寬線就多寬盛垦,所以測量mTextView的寬度
? ? ? ? ? ? ? ? ? ? int width =0;
? ? ? ? ? ? ? ? ? ? width = mTextView.getWidth();
? ? ? ? ? ? ? ? ? ? if (width ==0) {
mTextView.measure(0, 0);
? ? ? ? ? ? ? ? ? ? ? ? width = mTextView.getMeasuredWidth();
? ? ? ? ? ? ? ? ? ? }
//設(shè)置tab左右間距 湿弦,因為源碼中線的寬度是根據(jù)tabView的寬度來設(shè)置的,所以得注意這里不能使用Padding
? ? ? ? ? ? ? ? ? ? LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) tabView.getLayoutParams();
? ? ? ? ? ? ? ? ? ? //指示器寬度值設(shè)置
? ? ? ? ? ? ? ? ? ? params.width = width;
? ? ? ? ? ? ? ? ? ? //設(shè)置一下tabview的margin腾夯,不設(shè)置會連在一起
? ? ? ? ? ? ? ? ? ? params.leftMargin = dp10;
? ? ? ? ? ? ? ? ? ? params.rightMargin = dp10;
? ? ? ? ? ? ? ? ? ? tabView.setLayoutParams(params);
? ? ? ? ? ? ? ? ? ? tabView.invalidate();
? ? ? ? ? ? ? ? }
}catch (NoSuchFieldException e) {
e.printStackTrace();
? ? ? ? ? ? }catch (IllegalAccessException e) {
e.printStackTrace();
? ? ? ? ? ? }
}
});
}
```
然后在Tablayout渲染出來后調(diào)用此方法即可省撑。我們看看效果
現(xiàn)在的效果就變成了字多寬指示器就多寬了赌蔑。
這個效果我也是思考了挺久的,參考許多前輩的經(jīng)驗竟秫,總結(jié)了這篇文章,中間是否會有其他問題暫時還沒有發(fā)現(xiàn)跷乐,大家要是有什么更好的辦法肥败,請評論指教一番,后續(xù)有什么問題我將及時更新的愕提。另外熱烈歡迎大家來留言討論馒稍。