1. 程式人生 > >[Android]Tablayout:修改指示器indicator的寬度

[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:backgroundapp: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寬度的兩種方案,請自行選擇合適自己的方案。如有不正確,請指出,謝謝。