[Android]Tablayout:修改指示器indicator的寬度
一、問題描述:
最近接觸到了Tablayout,需求是要把Tablayout的下劃線寬度縮短,或者說使其可以進行自定寬度。
百度上面大多數利用反射,(具體可百度查詢),這種方法確實可以把下劃線變短,但是同時也會縮短Tab的點選區域,並且過於短後會影響Tab上TextView的UI顯示效果。總之,治標不治本,不是我想要的結果。
二、分析原始碼:
通過查詢資料以及對TabLayout的原始碼進行分析,發現原始碼中對下劃線color以及height都提供了介面,偏偏沒有給width提供介面。
進一步發現,下劃線是在draw()方法中畫出來的,並且定死了下劃線的寬度。所以,為啥預設的下劃線寬度總是和Tab寬度相同。
想要重寫draw方法所在類SlidingTabStrip,來達到目的,發現人家是private 私有內部類,且關於下劃線寬度的各種變數都是private,無法重寫。
三、解決方案:
網上普遍的反射不可以,又無法重寫,經過查詢資料和不斷嘗試,最終總算解決了問題,成功的自定義了下劃線寬度。
兩種方案:
1.將TabLayout原始碼copy至本地,修改draw方法,並新增自定義屬性,使其可以畫出自己想要的indicator寬度。
2.替換TabLayout,改用SmartTabLayout。
兩種方案均與ViewPager搭配使用
四、方案一:
1.提取原始碼。
在自己的專案路徑下新建包,Android Studio改為Project模式,找到design包,我的是27.1.1.版本。
External Libaries -> com.android.support:design-27.1.1 -> classes.jar -> android.support.design -> widget 目錄下
將TabLayout、AnimationUtils、TabItem、ThemeUtils四個檔案copy至自己新建的目錄下。
2.自定義屬性
tabLineOffset屬性為新增的自定義屬性,其餘copy系統屬性。
<!--Custom tabLayout attr -->
<declare-styleable name="TabLayout">
<attr name="tabIndicatorColor" format="color" />
<attr name="tabIndicatorHeight" format="dimension" />
<attr name="tabContentStart" format="dimension" />
<attr name="tabBackground" format="reference" />
<attr name="tabMode">
<enum name="scrollable" value="0" />
<enum name="fixed" value="1" />
</attr>
<attr name="tabGravity">
<enum name="fill" value="0" />
<enum name="center" value="1" />
</attr>
<attr name="tabMinWidth" format="dimension" />
<attr name="tabMaxWidth" format="dimension" />
<attr name="tabTextAppearance" format="reference" />
<attr name="tabTextColor" format="color" />
<attr name="tabSelectedTextColor" format="color" />
<attr name="tabPaddingStart" format="dimension" />
<attr name="tabPaddingTop" format="dimension" />
<attr name="tabPaddingEnd" format="dimension" />
<attr name="tabPaddingBottom" format="dimension" />
<attr name="tabPadding" format="dimension" />
<attr name="tabLineOffset" format="dimension"/>
</declare-styleable>
3.自定義屬性實現
在Tablayout檔案中,構造方法中新增自定義屬性。
//add custom attributes
mTabLineOffset = a.getDimensionPixelSize(R.styleable.TabLayout_tabLineOffset, 0);
修改draw方法。
@Override
public void draw(Canvas canvas) {
super.draw(canvas);
// Thick colored underline below the current selection
if (mIndicatorLeft >= 0 && mIndicatorRight > mIndicatorLeft) {
if (mTabLineOffset == 0) {
canvas.drawRect(mIndicatorLeft, getHeight() - mSelectedIndicatorHeight,
mIndicatorRight, getHeight(), mSelectedIndicatorPaint);
} else {
//Original TabLine Offset
int width = mIndicatorRight - mIndicatorLeft;
//Tab Center point coordinate
int tabCenter = mIndicatorLeft + width / 2;
RectF oval3 = new RectF(tabCenter - mTabLineOffset, getHeight() - mSelectedIndicatorHeight,
mIndicatorRight - width / 2 + mTabLineOffset, getHeight());
canvas.drawRoundRect(oval3, 30, 30, mSelectedIndicatorPaint);
}
}
}
4.設定下劃線寬度
在xml佈局中引入app:tabLineOffset="10dp"。通過檢視draw方法,
tabLineOffset並不是下劃線的實際寬度,想要widh=20dp,則設定app:tabLineOffset="10dp"即可。
<mysummary.TabLayout.two.my.TabLayout
android:id="@+id/tab"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorPrimary"
app:tabGravity="center"
app:tabIndicatorHeight="2dp"
app:tabLineOffset="10dp"
app:tabMode="scrollable"
app:tabSelectedTextColor="@android:color/holo_blue_light"
app:tabTextAppearance="@style/TabTextStyle"
app:tabTextColor="@android:color/white" />
5.檢查Activity中的TabLayout引用是否為自己的原始碼而不是引用的系統原始碼。
6.完成
注:TabLayout中
android:background 和 app:tabBackground 達到的背景效果相同,
但是app:tabBackground 會使Tab的點選效果消失(類似水波紋)。
五、方案二:
使用支援更多自定義的SmartTabLayout.有我們想要的自定義下劃線寬度屬性。
屬性 | 描述 |
---|---|
stl_indicatorAlwaysInCenter | 如果設定為true,選中的標籤總是顯示在中心(如報刊亭的谷歌應用程式),預設為false |
stl_indicatorWithoutPadding | 如果設定為真,畫出沒有填充標籤的指標,預設為假 |
stl_indicatorInFront | 在前面的下劃線,預設的假畫 |
stl_indicatorInterpolation | 指標的行為:: ‘linear’ or ‘smart’ |
stl_indicatorGravity | 指示器的位置: ‘bottom’ or ‘top’ or ‘center’, default ‘bottom’ |
stl_indicatorColor | 指示劑顏色 |
stl_indicatorColors | 該指標的多個顏色,可以設定每個標籤的顏色 |
stl_indicatorThickness | 指標的厚度 |
stl_indicatorWidth | 指標的寬度(width), default ‘auto’ |
stl_indicatorCornerRadius | 圓角半徑的指示器 |
stl_overlineColor | 頂線的顏色 |
stl_overlineThickness | 頂線厚度 |
stl_underlineColor | 底線的顏色 |
stl_underlineThickness | 底線的厚度 |
stl_dividerColor | 標籤的顏色之間的分隔 |
stl_dividerColors | 製表符分隔的多個顏色,可以設定每個標籤的顏色 |
stl_dividerThickness | 間隔(divider)的厚度 |
stl_defaultTabBackground | 背景中每個選項卡。一般來說,設定statelistdrawable |
stl_defaultTabTextAllCaps | 如果設定為真,所有標籤的標題將是大寫的,default true |
stl_defaultTabTextColor | 預設的選項卡的文字顏色 |
stl_defaultTabTextSize | 預設的選項卡的文字大小 |
stl_defaultTabTextHorizontalPadding | 預設情況下包含的選項卡的文字佈局填充 |
stl_defaultTabTextMinWidth | tab最小寬度 |
stl_customTabTextLayoutId | 佈局標識自定義選項卡。如果不指定佈局,使用預設選項卡 |
stl_customTabTextViewId | 自定義選項卡布局中的文字檢視標識。如果你不確定customtabtextlayoutid,不工作 |
stl_distributeEvenly | 如果設定為真,每個標籤都有相同的權重, default false |
stl_clickable | 如果設定為假,請禁用選項卡的選擇, default true |
stl_titleOffset | 如果設定為“auto_center,滑塊位置的標籤中會不斷向中心。如果指定一個維度將它從左邊偏移,預設24dp |
stl_drawDecorationAfterTab | Draw the decoration(indicator and lines) after drawing of tab, default false 繪製標籤後的裝飾(指標和線) |
1.新增依賴
compile 'com.ogaclejapan.smarttablayout:library:[email protected]'
2.Activity
public class SmartTablayoutActivity extends AppCompatActivity {
private SmartTabLayout mSmartTablayout;
private ViewPager mViewPager;
private MyAdapter mAdapter;
public String titles[];
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_smart_tablayout);
initView();
initData();
}
public void initView() {
mSmartTablayout = (SmartTabLayout) findViewById(R.id.smart_tablayout);
mViewPager = (ViewPager) findViewById(R.id.viewPager);
}
public void initData() {
titles = getResources().getStringArray(R.array.channel2);
mAdapter = new MyAdapter(getSupportFragmentManager(), titles);
mViewPager.setAdapter(mAdapter);
mSmartTablayout.setViewPager(mViewPager);
}
}
3.XML
<com.ogaclejapan.smarttablayout.SmartTabLayout xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/smart_tablayout"
android:layout_width="match_parent"
android:layout_height="40dp"
android:background="@color/colorPrimary"
app:stl_clickable="true"
app:stl_customTabTextLayoutId="@layout/view_tab_text"
app:stl_distributeEvenly="true"
app:stl_dividerThickness="0dp"
app:stl_indicatorColor="@color/colorAccent"
app:stl_indicatorGravity="bottom"
app:stl_indicatorInterpolation="linear"
app:stl_indicatorThickness="2dp"
app:stl_indicatorWidth="20dp"
app:stl_overlineThickness="0dp"
app:stl_titleOffset="auto_center"
app:stl_underlineThickness="0dp">
</com.ogaclejapan.smarttablayout.SmartTabLayout>
<android.support.v4.view.ViewPager
android:id="@+id/viewPager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
4.在Activity中SmartTabLayout用法基本與TabLayout相同,基本完工。執行程式碼可以發現下劃線寬度確實是可以自定義。
當然它還支援很多屬性的自定義。
5.SmartTabLayout中並沒有設定選中和未選中Tab時的效果,我們可以通過app:stl_customTabTextLayoutId屬性引入自定義設定。
view_tab_text.xml:
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/tab_text"
style="@style/Tabtext"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
android:paddingLeft="20dp"
android:paddingRight="20dp">
</TextView>
style.xml:
<style name="Tabtext">
<item name="android:textColor">@color/selector_tab_text</item>
<item name="android:textSize">20dp</item>
</style>
selector_tab_text.xml:
在這裡設定選中tab的字型顏色,和未選中tab的字型顏色。
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@android:color/holo_blue_light" android:state_selected="true" />
<item android:color="@color/colorWhite100" />
</selector>
6.因為引用了自定義Tab佈局,所以原生布局帶有的Tab點選效果消失(類似於水波紋)。
我們可以在 view_tab_text.xml 檔案中新增想要的水波紋效果。
android:foreground="@drawable/ripple_app_color"
ripple_app_color.xml: 水波紋效果
<?xml version="1.0" encoding="utf-8" ?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#292421">
</ripple>
7.完成
以上,是修改TabLayout indicator寬度的兩種方案,請自行選擇合適自己的方案。如有不正確,請指出,謝謝。