TabLayout設置下划線(Indicator)寬度


再戰TabLayout之下划線寬度

這周的需求搞定之后,想到之前有一個小瑕疵,反正沒什么事,索性較量較量

 

如圖官方原版就是小瑕疵,反射版本就是最終

 

解決方案-Demo源碼

先講解決方案。直接貼代碼(要在tabLayout添加完所有的tab后調用)

 

[java] view plain copy
  1. public void reflex(final TabLayout tabLayout){  
  2.     //了解源碼得知 線的寬度是根據 tabView的寬度來設置的  
  3.     tabLayout.post(new Runnable() {  
  4.         @Override  
  5.         public void run() {  
  6.             try {  
  7.                 //拿到tabLayout的mTabStrip屬性  
  8.                 LinearLayout mTabStrip = (LinearLayout) tabLayout.getChildAt(0);  
  9.   
  10.                 int dp10 = dip2px(tabLayout.getContext(), 10);  
  11.   
  12.                 for (int i = 0; i < mTabStrip.getChildCount(); i++) {  
  13.                     View tabView = mTabStrip.getChildAt(i);  
  14.   
  15.                     //拿到tabView的mTextView屬性  tab的字數不固定一定用反射取mTextView  
  16.                     Field mTextViewField = tabView.getClass().getDeclaredField("mTextView");  
  17.                     mTextViewField.setAccessible(true);  
  18.   
  19.                     TextView mTextView = (TextView) mTextViewField.get(tabView);  
  20.   
  21.                     tabView.setPadding(0, 0, 0, 0);  
  22.   
  23.                     //因為我想要的效果是   字多寬線就多寬,所以測量mTextView的寬度  
  24.                     int width = 0;  
  25.                     width = mTextView.getWidth();  
  26.                     if (width == 0) {  
  27.                         mTextView.measure(0, 0);  
  28.                         width = mTextView.getMeasuredWidth();  
  29.                     }  
  30.   
  31.                     //設置tab左右間距為10dp  注意這里不能使用Padding 因為源碼中線的寬度是根據 tabView的寬度來設置的  
  32.                     LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) tabView.getLayoutParams();  
  33.                     params.width = width ;  
  34.                     params.leftMargin = dp10;  
  35.                     params.rightMargin = dp10;  
  36.                     tabView.setLayoutParams(params);  
  37.   
  38.                     tabView.invalidate();  
  39.                 }  
  40.   
  41.             } catch (NoSuchFieldException e) {  
  42.                 e.printStackTrace();  
  43.             } catch (IllegalAccessException e) {  
  44.                 e.printStackTrace();  
  45.             }  
  46.         }  
  47.     });  
  48.   
  49. }  




 

 

問題解決思路

第一反應是找系統的方法和屬性

發現只有設置tabIndicatorHeight的屬性 並沒有寬度的屬性

 

接着百度,一百度就看到幾個博客,宣稱可以解決這個問題,我們先看看他們的解決方案

 

傳送門這種解決方案僅限於所有的tabView的text字數都是相同字數,比如所有的圖中所有的tab字數都是2個。其實思路是錯的,沒有研究源碼詳細實現

 

他的思路是設置tabView的padding為0,並且設置了margin

 

這種方案錯誤的原因是,tablayout會強制設置tabView的寬度為  幾個tabView中最寬的寬度,比如4個字的tabview和2個字的tabview的組合,兩個tabview的寬度強制為4個字的tabview的寬度

 

 下面會證實這一點

 

 

 

那只有查源碼了唄,tab的創建是 tablayout.addTab();方法構造的 具體代碼如下

[java] view plain copy
  1. tabLayout.addTab(tabLayout.newTab().setText("生鮮食品"));  



直接查這個方法,通過幾個重載方法(addTab(Tab tab)->addTab(Tab tab,boolean setSelected)->addTab( Tab tab, int position, boolean setSelecte);  跳轉如下代碼


 

從注釋看就是添加一個tab到這個layout上  具體實現是在addTabView(Tab tab)里面,繼續看這個方法

 


 

可以看到最后添加到mTabStrip中,我們再來看看TabView里面有什么東西

 


 

光從屬性可以看出TabView可以自定義的,而且並沒有發現Indicator線的痕跡,我猜測他可能放在layout(mTabStrip)里面,因為我以前寫這樣效果  這樣寫過,那我們就來看mTabStrip

 


 

查看類中,發現mSelectedIndicatorHeight,眼睛一亮,下划線高度!!,就是畫線的地方。追蹤mIndicatorLeft和mIndicatorRight的來路,幾經追蹤,發現如下代碼

 


 

如圖,selectedTitle就是TabView,直接獲取了左邊坐標和右邊坐標,也就說是線的寬度就是tabview的寬度,那疑問又來了,為什么我們兩個字的tabView和4個字的tabView是一樣寬度,先去看看SlidingTabStrip的onMeasure方法,如下圖

 


 

我日,我怎么感覺寫TabLayout這個類的人是強迫症,有沒有?第一個for循環干的事就是記錄下來,所有tabView中的最大寬度,第二個循環就是把所有的tabView的寬度設置為第一個循環得到的最大寬!!!

 

罪魁禍首是找到了,這時候能動態代理一個重寫onMeasure方法的SlidingTabStrip對象塞進去,也可以解決這個問題,你會發現SlidingTabStrip是private的!!!!!!!

 

思路一轉,系統是強制設置所有tabview的寬度為 最寬那個tabview的寬度,那我重新設置一遍tabView的寬度即可,解決問題(其實中間還嘗試過調用setIndicatorPosition方法,但是系統源碼,在多個時期調用這個方法,所以斃掉了)

那最上面的解決方案就來了

 

1、通過反射拿到SlidingTabStrip,通過遍歷拿到tabview,繼續通過反射拿到textview,然后設置Tabview的寬度為textview的寬度

 

2、為了美觀我們可以設置一下tabview的margin,不設置會連在一起

 

轉載 https://blog.csdn.net/qq_35473951/article/details/78653567


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM