關(guān)于Android改變TabLayout 下劃線(Indicator)寬度實(shí)踐總結(jié)

TabLayout我們再熟悉不過了,在開發(fā)中,像這種tab切換的需求都會(huì)用到TabLayout,它是由官方提供的一個(gè)控件,在support design 包中。使用起來非常簡單方便,交互效果也很不錯(cuò),能滿足我們開發(fā)中95%的需求。但是它有一個(gè)缺陷:不能改變Tab下劃線(Indicator)的寬度。本篇文章給你帶來改變Tab下劃線寬度的幾種方式:

1 . 通過反射設(shè)置Tab下劃線的寬度
2 . 通過TabLayout setCustomView 的方式
3 . 使用第三方開源庫。

一、通過反射的方式,改變TabLayout下劃線的寬度

首先我們看一下原生的TabLayout的效果(沒有任何修改):


Tablayout.png

gif演示:


gif演示.gif

上圖第一個(gè)固定模式(tabMode:fixed),下面是滾動(dòng)模式(tabMode:scrollable),可以看到,所有Tab下方的線(即Indicator)是一樣長的,不管Tab的內(nèi)容是長還是短。Tab indicator的長度與最長的Tab保持一致

TabLayout提供了tabIndicatorHeight 屬性來設(shè)置indicator的高度,但是沒有提供設(shè)置寬度的的api,要想改變indicator的寬度,就得去看看源碼indicator是怎么實(shí)現(xiàn)的。簡單的看一下源碼:

思維導(dǎo)圖.png

如上思維導(dǎo)圖,其中有兩個(gè)重點(diǎn)的東西, TabViewSlidingTabStrip,TabView就是我們所看到的Tab,SlidingTabStripTabView的父容器,繼承自LinearLayout,用來處理Tab滑動(dòng)相關(guān)操作,如動(dòng)畫,繪制Indicator等。

我們要研究indicator是怎么添加的,重點(diǎn)就在SlidingTabStrip 里了,這里我們看到了mSelectedIndicatorHeight,這就是我們設(shè)置Indicator的高度,在draw方法里有如下代碼:

 @Override
        public void draw(Canvas canvas) {
            super.draw(canvas);

            // Thick colored underline below the current selection
            if (mIndicatorLeft >= 0 && mIndicatorRight > mIndicatorLeft) {
                canvas.drawRect(mIndicatorLeft, getHeight() - mSelectedIndicatorHeight,
                        mIndicatorRight, getHeight(), mSelectedIndicatorPaint);
            }
        }

這就是繪制的選中Tab的Indicator,高度是mSelectedIndicatorHeight,寬是mIndicatorRight - mIndicatorLeft 。那么者兩個(gè)值是從哪兒來的呢?在updateIndicatorPosition方法中:

 private void updateIndicatorPosition() {
           // 選中的TabView
            final View selectedTitle = getChildAt(mSelectedPosition);
            int left, right;

            if (selectedTitle != null && selectedTitle.getWidth() > 0) {
                // left 和right 的值
                left = selectedTitle.getLeft();
                right = selectedTitle.getRight();

                if (mSelectionOffset > 0f && mSelectedPosition < getChildCount() - 1) {
                    // Draw the selection partway between the tabs
                    View nextTitle = getChildAt(mSelectedPosition + 1);
                    left = (int) (mSelectionOffset * nextTitle.getLeft() +
                            (1.0f - mSelectionOffset) * left);
                    right = (int) (mSelectionOffset * nextTitle.getRight() +
                            (1.0f - mSelectionOffset) * right);
                }
            } else {
                left = right = -1;
            }
           // 設(shè)置mIndicatorLeft和mIndicatorRight
            setIndicatorPosition(left, right);
        }

        void setIndicatorPosition(int left, int right) {
            if (left != mIndicatorLeft || right != mIndicatorRight) {
                // If the indicator's left/right has changed, invalidate
                mIndicatorLeft = left;
                mIndicatorRight = right;
                ViewCompat.postInvalidateOnAnimation(this);
            }
        }

從上面的代碼就可以看出,Indicator(Tab選中下劃線)的寬度其實(shí)就是TabView的寬度,那么TabView的寬度是多少呢?在SlidingTabStriponMeasure方法中,為TabView設(shè)置了寬度。請看代碼:

 @Override
        protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
             ...
             //以上省略
            if (mMode == MODE_FIXED && mTabGravity == GRAVITY_CENTER) {
                final int count = getChildCount();

                // First we'll find the widest tab
               //google的工程師注釋寫的非常清楚:第一步,找出寬度最長的Tab
                int largestTabWidth = 0;
                for (int i = 0, z = count; i < z; i++) {
                    View child = getChildAt(i);
                    if (child.getVisibility() == VISIBLE) {
                        largestTabWidth = Math.max(largestTabWidth, child.getMeasuredWidth());
                    }
                }

                if (largestTabWidth <= 0) {
                    // If we don't have a largest child yet, skip until the next measure pass
                    return;
                }

                final int gutter = dpToPx(FIXED_WRAP_GUTTER_MIN);
                boolean remeasure = false;

                if (largestTabWidth * count <= getMeasuredWidth() - gutter * 2) {
                    // If the tabs fit within our width minus gutters, we will set all tabs to have
                    // the same width
                  // 第二步:將所有Tab的寬度都設(shè)置為largestTabWidth
                    for (int i = 0; i < count; i++) {
                        final LinearLayout.LayoutParams lp =
                                (LayoutParams) getChildAt(i).getLayoutParams();
                        if (lp.width != largestTabWidth || lp.weight != 0) {
                            lp.width = largestTabWidth;
                            lp.weight = 0;
                            remeasure = true;
                        }
                    }
                } else {
                    // If the tabs will wrap to be larger than the width minus gutters, we need
                    // to switch to GRAVITY_FILL
                    mTabGravity = GRAVITY_FILL;
                    updateTabViews(false);
                    remeasure = true;
                }

            ...
            //以下省略
            }
        }

這個(gè)方法很簡單,一看就明白,有兩個(gè)步驟:

 1, 一個(gè)for循環(huán),找出寬度最大的一個(gè)TabView
 2, 再一個(gè)for 循環(huán),設(shè)置所有TabView的寬度為最長那個(gè)TabView的寬度,即largestTabWidth

這就知道為什么前面提到的所有Tab 一樣寬,不管長的還是短的。

另外一個(gè)點(diǎn): 上面的onMeasure 中,執(zhí)行的條件是mMode == MODE_FIXED && mTabGravity == GRAVITY_CENTER ,如果是其他條件,請看updateTabViews:

void updateTabViews(final boolean requestLayout) {
        for (int i = 0; i < mTabStrip.getChildCount(); i++) {
            View child = mTabStrip.getChildAt(i);
            child.setMinimumWidth(getTabMinWidth());
            updateTabViewLayoutParams((LinearLayout.LayoutParams) child.getLayoutParams());
            if (requestLayout) {
                child.requestLayout();
            }
        }
    }
    private void updateTabViewLayoutParams(LinearLayout.LayoutParams lp) {
        if (mMode == MODE_FIXED && mTabGravity == GRAVITY_FILL) {
            lp.width = 0;
            lp.weight = 1;
        } else {
            lp.width = LinearLayout.LayoutParams.WRAP_CONTENT;
            lp.weight = 0;
        }
    }

如果是MODE_FIXED,并且GRAVITY_FILL,則設(shè)置weight=1,所有TabView平分屏幕寬度,MODE_SCROLLABLE ,設(shè)置的WRAP_CONTENT

反射改變下劃線寬度

思路:知道了繪制Indicator的寬度是根據(jù)TabView的寬度來決定的,那么我們設(shè)置TabView的寬度就能改變indicator的寬,TabView的寬由其中的mTextView決定,因此,通過反射得到mTextView,設(shè)置它的寬度,就能改變Indicator的寬度,這也是網(wǎng)上看到的大多數(shù)的解決方法。

上代碼:

public static void setTabWidth(final TabLayout tabLayout, final int padding){
        tabLayout.post(new Runnable() {
            @Override
            public void run() {
                try {
                    //拿到tabLayout的mTabStrip屬性
                    LinearLayout mTabStrip = (LinearLayout) tabLayout.getChildAt(0);



                    for (int i = 0; i < mTabStrip.getChildCount(); i++) {
                        View tabView = mTabStrip.getChildAt(i);

                        //拿到tabView的mTextView屬性  tab的字?jǐn)?shù)不固定一定用反射取mTextView
                        Field mTextViewField = tabView.getClass().getDeclaredField("mTextView");
                        mTextViewField.setAccessible(true);

                        TextView mTextView = (TextView) mTextViewField.get(tabView);

                        tabView.setPadding(0, 0, 0, 0);

                        //因?yàn)槲蚁胍男Ч?  字多寬線就多寬,所以測量mTextView的寬度
                        int width = 0;
                        width = mTextView.getWidth();
                        if (width == 0) {
                            mTextView.measure(0, 0);
                            width = mTextView.getMeasuredWidth();
                        }

                        //設(shè)置tab左右間距 注意這里不能使用Padding 因?yàn)樵创a中線的寬度是根據(jù) tabView的寬度來設(shè)置的
                        LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) tabView.getLayoutParams();
                        params.width = width ;
                        params.leftMargin = padding;
                        params.rightMargin = padding;
                        tabView.setLayoutParams(params);

                        tabView.invalidate();
                    }

                } catch (NoSuchFieldException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        });

    }

效果圖如下:


改變長度的Indicator演示.gif

提醒:這種方式改變Indicator最短也就Tab內(nèi)容的寬度,如果設(shè)置很短,Tab內(nèi)容就顯示不下,如下圖:

Tab內(nèi)容顯示不下.png

二、通過TabLayout setCustomView 的方式

第一種通過反射的方式設(shè)置Indicator寬度,最短只能Tab內(nèi)容的寬度,如果設(shè)計(jì)師要所有選中的Tab下的Indicator都設(shè)置一個(gè)指定的寬度,這種就不行了。TabLayout可以設(shè)置自定義View,可以通過這種方法來達(dá)到目的。

1, 將TabLayout 的tabIndicatorHeight 設(shè)置為0
2,通過TabLayout 的setCustomView方式添加Tab
3, 在onTabSelected 回調(diào)種,處理Tab選中和未選中的狀態(tài);
4,為了方便使用,封裝成一個(gè)通用的View

首先看布局:
enhance_tab_layout.xml:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <android.support.design.widget.TabLayout
        android:id="@+id/enhance_tab_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:tabIndicatorHeight="0dp"
        >
    </android.support.design.widget.TabLayout>
</FrameLayout>

Tab item 布局:tab_item_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:gravity="center"
android:layout_width="match_parent"
android:layout_height="match_parent">

<TextView
    android:id="@+id/tab_item_text"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:textSize="13sp"
    android:text="首頁"
    android:textColor="#333333"
    />
<View
    android:id="@+id/tab_item_indicator"
    android:layout_width="30dp"
    android:layout_height="2dp"
    android:layout_marginTop="5dp"
    android:background="@color/colorAccent"
    android:visibility="invisible"
    />
</LinearLayout>

如上,TextView顯示Tab內(nèi)容,下面的View就是Tab下面的Indicator(下劃線)。
自己定義的View,寬度隨便你改。

添加Tab的時(shí)候使用setCustomView 方法:

 /**
     * 添加tab
     * @param tab
     */
    public void addTab(String tab){
        mTabList.add(tab);
        View customView = getTabView(getContext(),tab,mIndicatorWidth,mIndicatorHeight,mTabTextSize);
        mCustomViewList.add(customView);
        mTabLayout.addTab(mTabLayout.newTab().setCustomView(customView));
    }


    /**
     * 獲取Tab 顯示的內(nèi)容
     *
     * @param context
     * @param
     * @return
     */
    public static View getTabView(Context context,String text,int indicatorWidth,int indicatorHeight,int textSize) {
        View view = LayoutInflater.from(context).inflate(R.layout.tab_item_layout, null);
        TextView tabText = (TextView) view.findViewById(R.id.tab_item_text);
        if(indicatorWidth>0){
            View indicator = view.findViewById(R.id.tab_item_indicator);
            ViewGroup.LayoutParams layoutParams = indicator.getLayoutParams();
            layoutParams.width  = indicatorWidth;
            layoutParams.height = indicatorHeight;
            indicator.setLayoutParams(layoutParams);
        }
        tabText.setTextSize(textSize);
        tabText.setText(text);
        return view;
    }

然后在onTabSelected中處理狀態(tài):

  @Override
        public void onTabSelected(TabLayout.Tab tab) {
            mViewPager.setCurrentItem(tab.getPosition());
            EnhanceTabLayout mTabLayout = mTabLayoutRef.get();
            if(mTabLayoutRef!=null){
                List<View> customViewList = mTabLayout.getCustomViewList();
                if(customViewList == null || customViewList.size() ==0){
                    return;
                }
                for (int i=0;i<customViewList.size();i++){
                    View view = customViewList.get(i);
                    if(view == null){
                        return;
                    }
                    TextView text = (TextView) view.findViewById(R.id.tab_item_text);
                    View indicator = view.findViewById(R.id.tab_item_indicator);
                    if(i == tab.getPosition()){ // 選中狀態(tài)
                        text.setTextColor(mTabLayout.mSelectTextColor);
                        indicator.setBackgroundColor(mTabLayout.mSelectIndicatorColor);
                        indicator.setVisibility(View.VISIBLE);
                    }else{// 未選中狀態(tài)
                        text.setTextColor(mTabLayout.mUnSelectTextColor);
                        indicator.setVisibility(View.INVISIBLE);
                    }
                }
            }

        }

代碼其實(shí)挺簡單的,但是如果項(xiàng)目中多處使用到,都這樣來處理的話,就顯得麻煩,因此,我們通過自定義View的方式將這些代碼瘋轉(zhuǎn)成1個(gè)通用的TabLayoutView。如下:

EnhanceTabLayout.java

/**
 *  對 support Design 包中的TabLayout包裝
 *  主要實(shí)現(xiàn)功能:更改indicator 的長度
 * Created by zhouwei on 2018/5/18.
 */

public class EnhanceTabLayout extends FrameLayout {
    private TabLayout mTabLayout;
    private List<String> mTabList;
    private List<View> mCustomViewList;
    private int mSelectIndicatorColor;
    private int mSelectTextColor;
    private int mUnSelectTextColor;
    private int mIndicatorHeight;
    private int mIndicatorWidth;
    private int mTabMode;
    private int mTabTextSize;

    public EnhanceTabLayout(@NonNull Context context) {
        super(context);
        init(context,null);
    }

    public EnhanceTabLayout(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init(context,attrs);
    }

    public EnhanceTabLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context,attrs);
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    public EnhanceTabLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init(context,attrs);
    }

    private void readAttr(Context context,AttributeSet attrs){
        TypedArray typedArray = context.obtainStyledAttributes(attrs,R.styleable.EnhanceTabLayout);
        mSelectIndicatorColor = typedArray.getColor(R.styleable.EnhanceTabLayout_tabIndicatorColor,context.getResources().getColor(R.color.colorAccent));
        mUnSelectTextColor =  typedArray.getColor(R.styleable.EnhanceTabLayout_tabTextColor, Color.parseColor("#666666"));
        mSelectTextColor = typedArray.getColor(R.styleable.EnhanceTabLayout_tabSelectTextColor,context.getResources().getColor(R.color.colorAccent));
        mIndicatorHeight = typedArray.getDimensionPixelSize(R.styleable.EnhanceTabLayout_tabIndicatorHeight,1);
        mIndicatorWidth = typedArray.getDimensionPixelSize(R.styleable.EnhanceTabLayout_tabIndicatorWidth,0);
        mTabTextSize = typedArray.getDimensionPixelSize(R.styleable.EnhanceTabLayout_tabTextSize,13);
        mTabMode = typedArray.getInt(R.styleable.EnhanceTabLayout_tab_Mode,2);
        typedArray.recycle();
    }

    private void init(Context context,AttributeSet attrs){
        readAttr(context,attrs);

        mTabList = new ArrayList<>();
        mCustomViewList = new ArrayList<>();
        View view = LayoutInflater.from(getContext()).inflate(R.layout.enhance_tab_layout,this,true);
        mTabLayout = view.findViewById(R.id.enhance_tab_view);

        // 添加屬性
        mTabLayout.setTabMode(mTabMode == 1 ? TabLayout.MODE_FIXED:TabLayout.MODE_SCROLLABLE);
        mTabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
            @Override
            public void onTabSelected(TabLayout.Tab tab) {
                // onTabItemSelected(tab.getPosition());
                // Tab 選中之后,改變各個(gè)Tab的狀態(tài)
                for (int i=0;i<mTabLayout.getTabCount();i++){
                    View view = mTabLayout.getTabAt(i).getCustomView();
                    if(view == null){
                        return;
                    }
                    TextView text = (TextView) view.findViewById(R.id.tab_item_text);
                    View indicator = view.findViewById(R.id.tab_item_indicator);
                    if(i == tab.getPosition()){ // 選中狀態(tài)
                        text.setTextColor(mSelectTextColor);
                        indicator.setBackgroundColor(mSelectIndicatorColor);
                        indicator.setVisibility(View.VISIBLE);
                    }else{// 未選中狀態(tài)
                        text.setTextColor(mUnSelectTextColor);
                        indicator.setVisibility(View.INVISIBLE);
                    }
                }

            }

            @Override
            public void onTabUnselected(TabLayout.Tab tab) {

            }

            @Override
            public void onTabReselected(TabLayout.Tab tab) {

            }
        });
    }

    public List<View> getCustomViewList(){
        return mCustomViewList;
    }

    public void addOnTabSelectedListener (TabLayout.OnTabSelectedListener onTabSelectedListener){
        mTabLayout.addOnTabSelectedListener(onTabSelectedListener);
    }

    /**
     * 與TabLayout 聯(lián)動(dòng)
     * @param viewPager
     */
    public void setupWithViewPager(@Nullable ViewPager viewPager) {
        mTabLayout.addOnTabSelectedListener(new ViewPagerOnTabSelectedListener(viewPager,this));
    }




    /**
     * retrive TabLayout Instance
     * @return
     */
    public TabLayout getTabLayout(){
        return mTabLayout;
    }

    /**
     * 添加tab
     * @param tab
     */
    public void addTab(String tab){
        mTabList.add(tab);
        View customView = getTabView(getContext(),tab,mIndicatorWidth,mIndicatorHeight,mTabTextSize);
        mCustomViewList.add(customView);
        mTabLayout.addTab(mTabLayout.newTab().setCustomView(customView));
    }

    public static class ViewPagerOnTabSelectedListener implements TabLayout.OnTabSelectedListener{

        private final ViewPager mViewPager;
        private final WeakReference<EnhanceTabLayout> mTabLayoutRef;

        public ViewPagerOnTabSelectedListener(ViewPager viewPager,EnhanceTabLayout enhanceTabLayout) {
            mViewPager = viewPager;
            mTabLayoutRef = new WeakReference<EnhanceTabLayout>(enhanceTabLayout);
        }

        @Override
        public void onTabSelected(TabLayout.Tab tab) {
            mViewPager.setCurrentItem(tab.getPosition());
            EnhanceTabLayout mTabLayout = mTabLayoutRef.get();
            if(mTabLayoutRef!=null){
                List<View> customViewList = mTabLayout.getCustomViewList();
                if(customViewList == null || customViewList.size() ==0){
                    return;
                }
                for (int i=0;i<customViewList.size();i++){
                    View view = customViewList.get(i);
                    if(view == null){
                        return;
                    }
                    TextView text = (TextView) view.findViewById(R.id.tab_item_text);
                    View indicator = view.findViewById(R.id.tab_item_indicator);
                    if(i == tab.getPosition()){ // 選中狀態(tài)
                        text.setTextColor(mTabLayout.mSelectTextColor);
                        indicator.setBackgroundColor(mTabLayout.mSelectIndicatorColor);
                        indicator.setVisibility(View.VISIBLE);
                    }else{// 未選中狀態(tài)
                        text.setTextColor(mTabLayout.mUnSelectTextColor);
                        indicator.setVisibility(View.INVISIBLE);
                    }
                }
            }

        }

        @Override
        public void onTabUnselected(TabLayout.Tab tab) {
            // No-op
        }

        @Override
        public void onTabReselected(TabLayout.Tab tab) {
            // No-op
        }
    }

    /**
     * 獲取Tab 顯示的內(nèi)容
     *
     * @param context
     * @param
     * @return
     */
    public static View getTabView(Context context,String text,int indicatorWidth,int indicatorHeight,int textSize) {
        View view = LayoutInflater.from(context).inflate(R.layout.tab_item_layout, null);
        TextView tabText = (TextView) view.findViewById(R.id.tab_item_text);
        if(indicatorWidth>0){
            View indicator = view.findViewById(R.id.tab_item_indicator);
            ViewGroup.LayoutParams layoutParams = indicator.getLayoutParams();
            layoutParams.width  = indicatorWidth;
            layoutParams.height = indicatorHeight;
            indicator.setLayoutParams(layoutParams);
        }
        tabText.setTextSize(textSize);
        tabText.setText(text);
        return view;
    }

暴露了一些常用方法和原生TabLayout 的幾個(gè)重要屬性,自定義屬性如下:

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <declare-styleable name="EnhanceTabLayout">
        <attr name="tab_Mode" format="enum">
            <enum name="mode_fixed" value="1"/>
            <enum name="mode_scrollable" value="2"/>
        </attr>
        <attr name="tabIndicatorColor" format="color"/>
        <attr name="tabSelectTextColor" format="color"/>
        <attr name="tabTextColor" format="color"/>
        <attr name="tabIndicatorHeight" format="dimension"/>
        <attr name="tabIndicatorWidth" format="dimension"/>
        <attr name="tabTextSize" format="dimension"/>
    </declare-styleable>
</resources>

好了,這樣就封裝了一個(gè)可以改變Indicator 寬度的TabLayout,看一下怎么用,xml布局如下:

 <com.example.codoon.customtablayout.EnhanceTabLayout
       android:id="@+id/enhance_tab_layout"
       android:layout_marginTop="30dp"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       app:tabIndicatorHeight="2dp"
       app:tabIndicatorWidth="30dp"
       app:tabTextColor="#999999"
       app:tab_Mode="mode_scrollable"
       app:tabSelectTextColor="@color/colorPrimary"
       app:tabIndicatorColor="@color/colorPrimary"
       app:tabTextSize="6sp"
       >

   </com.example.codoon.customtablayout.EnhanceTabLayout>

Activity中代碼如下:

        mEnhanceTabLayout = findViewById(R.id.enhance_tab_layout);
        mEnhanceTabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
            @Override
            public void onTabSelected(TabLayout.Tab tab) {
                 Log.e("log","onTabSelected");
            }

            @Override
            public void onTabUnselected(TabLayout.Tab tab) {

            }

            @Override
            public void onTabReselected(TabLayout.Tab tab) {

            }
        });
        for(int i=0;i<sTitle.length;i++){
            mEnhanceTabLayout.addTab(sTitle[i]);
        }
        mEnhanceTabLayout.setupWithViewPager(mViewPager);
        List<Fragment> fragments = new ArrayList<>();
        for(int i=0;i<sTitle.length;i++){
            fragments.add(ItemFragment.newInstance(sTitle[i]));
        }

        MyAdapter adapter = new MyAdapter(getSupportFragmentManager(),fragments, Arrays.asList(sTitle));
        mViewPager.setAdapter(adapter);
        mViewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(mEnhanceTabLayout.getTabLayout()));
        mEnhanceTabLayout.setupWithViewPager(mViewPager);

注意,如果是配合ViewPager使用,需要下面兩行代碼,單獨(dú)使用則不需要:

 mViewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(mEnhanceTabLayout.getTabLayout()));
 mEnhanceTabLayout.setupWithViewPager(mViewPager);

最后看一下效果:(圖中第二個(gè)TabLayout)

自定義View方式.gif

三、第三方開源庫

如果前面2中方式都滿足不了你的需求的話,你可以使用第三方庫,也有一些不錯(cuò)的開源庫,這里推薦2個(gè)。
**1 , MagicIndicator **

github:https://github.com/hackware1993/MagicIndicator
star:4.4k

MagicIndicator ,使用方便,還有多種模式可以選擇。包括:


indicator.png

有興趣的可以去試一下。

repositories {
    ...
    maven {
        url "https://jitpack.io"
    }
}

dependencies {
    ...
    compile 'com.github.hackware1993:MagicIndicator:1.5.0'
}

布局文件:

<net.lucode.hackware.magicindicator.MagicIndicator
      android:id="@+id/magic_indicator"
      android:layout_width="match_parent"
      android:layout_height="49dp">

  </net.lucode.hackware.magicindicator.MagicIndicator>

代碼中:

  MagicIndicator magicIndicator = (MagicIndicator) findViewById(R.id.magic_indicator);
        CommonNavigator commonNavigator = new CommonNavigator(this);
        commonNavigator.setAdapter(new CommonNavigatorAdapter() {

            @Override
            public int getCount() {
                return sTitle == null ? 0 : sTitle.length;
            }

            @Override
            public IPagerTitleView getTitleView(Context context, final int index) {
                ColorTransitionPagerTitleView colorTransitionPagerTitleView = new ColorTransitionPagerTitleView(context);
                colorTransitionPagerTitleView.setNormalColor(Color.GRAY);
                colorTransitionPagerTitleView.setSelectedColor(Color.BLACK);
                colorTransitionPagerTitleView.setText(sTitle[index]);
                colorTransitionPagerTitleView.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        mViewPager.setCurrentItem(index);
                    }
                });
                return colorTransitionPagerTitleView;
            }

            @Override
            public IPagerIndicator getIndicator(Context context) {
                LinePagerIndicator indicator = new LinePagerIndicator(context);
                indicator.setMode(LinePagerIndicator.MODE_EXACTLY);
                //設(shè)置indicator的寬度
                indicator.setLineWidth(TabUtils.dp2px(context,20));
                return indicator;
            }
        });
        magicIndicator.setNavigator(commonNavigator);
        ViewPagerHelper.bind(magicIndicator,mViewPager);

效果圖如下,圖中最后一個(gè)TabLayout:


MagicIndicator.gif

2 , FlycoTabLayout
github:https://github.com/H07000223/FlycoTabLayout
star:6.5k

功能和MagicIndicator差不多,都支持多種Indicator效果:

FlycoTabLayout.gif

具體使用請看github 詳細(xì)介紹。

四、總結(jié)

本文總結(jié)了改變TabLayout下劃線(indicator)寬度的幾種方式,使用的時(shí)候根據(jù)自己的需求選擇,在原生控件能做的情況下,盡量使用原生控件,畢竟導(dǎo)入三方庫需要一些額外的成本。如果你還有更好的方式,歡迎評論區(qū)留言討論。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容