TabLayout is an official control provided in the Support Design package. It is very simple to use, and the interaction effect is very good, which can meet 95% of our development needs. But it has one drawback: it doesn’t change the width of the Tab Indicator. This article gives you several ways to change the width of the Tab underline:

1. Set the width of the Tab underline by reflection2. By TabLayout setCustomView3. Use third-party open source libraries.Copy the code

Change the width of the TabLayout underline by reflection

First let’s take a look at the original TabLayout (without any changes) :

GIF demo:

As you can see from the first tabMode (fixed) and the next tabMode (scrollable), the indicators under all tabs are the same length regardless of whether the Tab content is long or short. The Tab Indicator is the same length as the longest Tab.

TabLayout provides the tabIndicatorHeight property to set the height of the indicator, but there is no API to set the width of the indicator. To change the width of the indicator, you need to look at the source indicator implementation. A brief look at the source code:

In the mind map above, there are two key things,TabView and SlidingTabStrip. TabView is the Tab we see, SlidingTabStrip is the parent of TabView, Inherited from LinearLayout, used to handle Tab sliding related operations, such as animation, drawing Indicator, etc.

Here we see the mSelectedIndicatorHeight. This is the height we set the indicator to. In the draw method we have the following code:

 @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); }}Copy the code

This is the drawing of the selected Tab Indicator, is highly mSelectedIndicatorHeight, is mIndicatorRight mIndicatorLeft wide. So where do these two values come from? In the updateIndicatorPosition method:

 private void updateIndicatorPosition(a) {
           // Select TabView
            final View selectedTitle = getChildAt(mSelectedPosition);
            int left, right;

            if(selectedTitle ! =null && selectedTitle.getWidth() > 0) {
                // Left and right values
                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.0 f - mSelectionOffset) * left);
                    right = (int) (mSelectionOffset * nextTitle.getRight() +
                            (1.0 f- mSelectionOffset) * right); }}else {
                left = right = -1;
            }
           // Set mIndicatorLeft and 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); }}Copy the code

The width of the Indicator is the width of the TabView. What is the width of the TabView? In the onMeasure method of SlidingTabStrip, the width of the TabView is set. Look at the code:

 @Override
        protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec); .// The above is omitted
            if (mMode == MODE_FIXED && mTabGravity == GRAVITY_CENTER) {
                final int count = getChildCount();

                // First we'll find the widest tab
               // The Google engineer notes are very clear: first, find the Tab with the longest width
                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
                  // Step 2: Set all Tab widths to 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; }...// the following is omitted}}Copy the code

This method is very simple, it is easy to see, there are two steps:

 1, aforLoop to find the TabView with the largest width2And then aforLoop to set the width of all TabViews to the width of the longest TabView, i.e. LargestTabWidthCopy the code

That’s why all the tabs mentioned earlier are the same width, long and short.

MMode == MODE_FIXED && mTabGravity == GRAVITY_CENTER

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(); }}}Copy the code
    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; }}Copy the code

If it is MODE_FIXED and GRAVITY_FILL, set weight=1, all tabViews split screen width, MODE_SCROLLABLE, set WRAP_CONTENT.

Reflection changes the underline width

Ideas: Knowing that the width of the Indicator is determined by the width of the TabView, we can change the width of the Indicator by setting the width of the TabView. The width of the TabView is determined by the mTextView inside of the TabView. Therefore, by reflecting the mTextView, set the width of the mTextView. You can change the width of the Indicator, which is the most common solution you see online.

The code:

public static void setTabWidth(final TabLayout tabLayout, final int padding){
        tabLayout.post(new Runnable() {
            @Override
            public void run(a) {
                try {
                    // Get the mTabStrip property of tabLayout
                    LinearLayout mTabStrip = (LinearLayout) tabLayout.getChildAt(0);



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

                        // Get the mTextView property of tabView
                        Field mTextViewField = tabView.getClass().getDeclaredField("mTextView");
                        mTextViewField.setAccessible(true);

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

                        tabView.setPadding(0.0.0.0);

                        // Since I want the line to be as wide as the word, I measure the width of the mTextView
                        int width = 0;
                        width = mTextView.getWidth();
                        if (width == 0) {
                            mTextView.measure(0.0);
                            width = mTextView.getMeasuredWidth();
                        }

                        Note that no Padding can be used here because the width of the source line is set according to the width of the tabViewLinearLayout.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(); }}}); }Copy the code

The renderings are as follows:

Note: This changes the Indicator to the minimum Tab width. If you set the Indicator to very short, the Tab content will not display as shown below:

Second, through TabLayout setCustomView

The first option is to set the Indicator width by reflection. The minimum is the width of the Tab content. If the designer wants all the indicators under the selected Tab to be set to a specified width, this will not work. TabLayout allows you to set up custom views, which you can do in this way.

1, set TabLayout's tabIndicatorHeight to0
2Add a Tab using the setCustomView method of TabLayout3In the onTabSelected callback, handle Tab checked and unchecked states;4, encapsulated into a generic View for ease of useCopy the code

First look at the layout: enhance_tab_layout.xml:

<? The 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>Copy the code

Tab item layout: tab_item_layout.xml

<? The 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=" #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>Copy the code

As shown above, TextView displays Tab content and the View below is the Indicator below the Tab. You define your own View, you can change the width.

Add Tab using setCustomView method:

 /** * add 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));
    }


    /** * get the Tab content **@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;
    }
Copy the code

Then handle the state in onTabSelected:

  @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()){ // Select status
                        text.setTextColor(mTabLayout.mSelectTextColor);
                        indicator.setBackgroundColor(mTabLayout.mSelectIndicatorColor);
                        indicator.setVisibility(View.VISIBLE);
                    }else{// State is not selectedtext.setTextColor(mTabLayout.mUnSelectTextColor); indicator.setVisibility(View.INVISIBLE); }}}}Copy the code

The code is actually quite simple, but if the project is used in many places, it will be troublesome to handle, so we use custom View to turn this code into a generic TabLayoutView. As follows:

EnhanceTabLayout.java

** * 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);

        // Add attributes
        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 Changes the status of each Tab after it is selected
                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()){ // Select status
                        text.setTextColor(mSelectTextColor);
                        indicator.setBackgroundColor(mSelectIndicatorColor);
                        indicator.setVisibility(View.VISIBLE);
                    }else{// State is not selectedtext.setTextColor(mUnSelectTextColor); indicator.setVisibility(View.INVISIBLE); }}}@Override
            public void onTabUnselected(TabLayout.Tab tab) {}@Override
            public void onTabReselected(TabLayout.Tab tab) {}}); }public List<View> getCustomViewList(a){
        return mCustomViewList;
    }

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

    /** * Interwork with TabLayout *@param viewPager
     */
    public void setupWithViewPager(@Nullable ViewPager viewPager) {
        mTabLayout.addOnTabSelectedListener(new ViewPagerOnTabSelectedListener(viewPager,this));
    }




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

    /** * add 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()){ // Select status
                        text.setTextColor(mTabLayout.mSelectTextColor);
                        indicator.setBackgroundColor(mTabLayout.mSelectIndicatorColor);
                        indicator.setVisibility(View.VISIBLE);
                    }else{// State is not selectedtext.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}}/** * get the Tab content **@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;
    }
Copy the code

It exposes some common methods and several important properties of the native TabLayout. The custom properties are as follows:

<? The 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>Copy the code

Ok, this encapsulates a TabLayout that can change the width of the Indicator. To see how it works, the XML layout is as follows:

 <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>
Copy the code

The code for the Activity is as follows:

        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);
Copy the code

Note that the following two lines are required if used with the ViewPager, but not alone:

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

Finally, take a look :(second TabLayout)

Third party open source library

If neither of the above two methods meets your needs, you can use third-party libraries. There are some good open source libraries, and two of them are recommended. **1 , MagicIndicator **

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

MagicIndicator, easy to use, and multiple modes to choose from. Include:

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

dependencies {
    ...
    compile 'com. Making. Hackware1993: MagicIndicator: 1.5.0'
}
Copy the code

Layout file:

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

In the code:

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

            @Override
            public int getCount(a) {
                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);
                // Set the width of indicator
                indicator.setLineWidth(TabUtils.dp2px(context,20));
                returnindicator; }}); magicIndicator.setNavigator(commonNavigator); ViewPagerHelper.bind(magicIndicator,mViewPager);Copy the code

The final TabLayout is as follows:

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

Functions similar to magicIndicators, both support multiple indicators:

Please refer to Github for details.

Four,

This article summarized several ways to change the width of TabLayout underline (Indicator). Use them according to your own needs. If native controls can do it, use native controls as much as possible. If you have a better idea, feel free to leave a comment in the comments section.

More Android dry goods articles, pay attention to the public number [Android technology grocery store]