android TabLayout的指示器寬度問題
最近碰到一個需求,因為是我比較感興趣的TabLayout的,所以記錄一下吧。
- 產品需求:希望上部導航欄中的指示器寬度略大于文字寬度;
- 技術方案:TabLayout配合ViewPager;
- 問題分析: 原生TabLayout的指示器寬度等于每個tab的寬度,遠大于 tab內文字標題的寬度。
原因分析:
TabLayout(TL)繼承自HorizontalScrollView,其只能添加一個子控件,這個子控件便是TL內部私有類–SlidingTabStrip,其繼承自LinearLayout。指示器怎么加上的呢?便是在該類的onDraw方法中:
@Override public void draw(Canvas canvas) { super.draw(canvas); // Thick colored underline below the current selection if (mIndicatorLeft >= 0 && mIndicatorRight > mIndicatorLeft) { canvas.drawRect(mIndicatorLeft, mIndicatorRight, getHeight(), mSelectedIndicatorPaint); } }
即指示器是與這個SlidingTabStrip容器伴生存在,其寬度,由mIndicatorLeft和mIndicatorRight確定,而這二者,由tab的寬度決定,因為本文不會詳細描述TL的源碼,所以這里直接報出結論:這個指示器的寬度設置由tab寬度決定,而tab在mode=fix情況下,是符合linearLayout中weight控制的,因此,也沒法通過tab的寬度來影響指示器的寬度,比較囧的是,源碼中也沒給tab設置個Margin什么的,另外,源碼中也沒有暴露set等方法來改變指示器寬度,否則也不會有此問題了。
解決方案1:
百度的方案基本集中在反射,使用麻煩,有時還不好用。
這個的思路來自stackoverflow,大致過程是 由TL拿到其唯一的子類,即SlidingTabStrip,然后遍歷再拿到其各子View,然后為每個子View設置Margin,這就相當于給每個tab設置margin,那么指示器的寬度自然也就跟著改變了。show code:
public static void reduceMarginsInTabs(TabLayout tabLayout, int marginOffset) { View tabStrip = tabLayout.getChildAt(0); if (tabStrip instanceof ViewGroup) { ViewGroup tabStripGroup = (ViewGroup) tabStrip; for (int i = 0; i < ((ViewGroup) tabStrip).getChildCount(); i++) { View tabView = tabStripGroup.getChildAt(i); if (tabView.getLayoutParams() instanceof ViewGroup.MarginLayoutParams) { ((ViewGroup.MarginLayoutParams) tabView.getLayoutParams()).leftMargin = marginOffset; ((ViewGroup.MarginLayoutParams) tabView.getLayoutParams()).rightMargin = marginOffset; } } tabLayout.requestLayout(); } }
這種方式的限制是:最多只能讓指示器與tab等寬,無法繼續(xù)減小指示器的寬度。
解決方案2:
本方案屬于自定制指示器顯示,相對比較靈活,能解決方案1的tab等寬問題,但是其缺點是不能保留指示器的動畫。具體過程:
TL中tab可以設置自定義view,方法是setCustomView(@Nullable View view) ,也就是說,完全可以不用TL中那套,直接自定義布局即可。在tab源碼的update方法中有這么一句:
mCustomTextView = (TextView) custom.findViewById(android.R.id.text1); if (mCustomTextView != null) { mDefaultMaxLines = TextViewCompat.getMaxLines(mCustomTextView); } mCustomIconView = (ImageView) custom.findViewById(android.R.id.icon);
里面的android.R.id.text1和android.R.id.icon就是TL中tab能跟隨滑動改變狀態(tài)的兩個view的id,我們自定義的時候可以讓對應的view也這么設置id即可。而指示器,大可屏蔽原生TL的,直接在自定義布局的合適位置,加個view就行。
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關文章
Android Studio提示inotify大小不足的解決辦法
大家在使用Android Studio導入AOSP源碼的時候,可能會遇到inotify大小不足的問題,這篇文章就給大家介紹了怎么解決這個問題的方法,有需要的朋友們可以參考借鑒。2016-09-09Android、iOS和Windows Phone中的推送技術詳解
這篇文章主要介紹了Android、iOS和Windows Phone中的推送技術詳解,推送技術的實現通常會使用服務端向客戶端推送消息的方式,也就是說客戶端通過用戶名、Key等ID注冊到服務端后,在服務端就可以將消息向所有活動的客戶端發(fā)送,需要的朋友可以參考下2015-01-01Android入門之TabHost與TabWidget實例解析
這篇文章主要介紹了Android入門之TabHost與TabWidget,對于Android初學者有一定的學習借鑒價值,需要的朋友可以參考下2014-08-08