TabLayout not filling width when tabMode set to 'scrollable'

59,074

Solution 1

I guess this is the simpliest way to achieve what you want.

public class CustomTabLayout extends TabLayout {
    public CustomTabLayout(Context context) {
        super(context);
    }

    public CustomTabLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public CustomTabLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        try {
            if (getTabCount() == 0)
                return;
            Field field = TabLayout.class.getDeclaredField("mTabMinWidth");
            field.setAccessible(true);
            field.set(this, (int) (getMeasuredWidth() / (float) getTabCount()));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Solution 2

androidx version:

<androidx.viewpager.widget.ViewPager
    android:id="@+id/view_pager"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layout_behavior="@string/appbar_scrolling_view_behavior" >
    <com.google.android.material.tabs.TabLayout
        android:id="@+id/tabs"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:tabMaxWidth="0dp"
        app:tabGravity="fill"
        app:tabMode="fixed"
        />
</androidx.viewpager.widget.ViewPager>

With more than 5 tabs

***** BELOW IS OLD ANSWER *****

Try this one, it's a workaround which sets tabMaxWidth="0dp", tabGravity="fill" and tabMode="fixed".

 <android.support.v4.view.ViewPager
     android:id="@+id/container"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     app:layout_behavior="@string/appbar_scrolling_view_behavior">
     <android.support.design.widget.TabLayout
         android:id="@+id/tabs"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         app:tabMaxWidth="0dp"
         app:tabGravity="fill"
         app:tabMode="fixed"/>
</android.support.v4.view.ViewPager>

Screenshot on a 10 inch tablet:

screenshot

Solution 3

Instead of creating custom TabLayout and hacking around or creating more layouts which acts as wrapper around TabLayout only for background. Try this,

<android.support.design.widget.TabLayout
    android:id="@+id/tabs"
    style="@style/MyColorAccentTabLayout"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    <!-- Instead of setting app:tabBackground -->
    android:background="@color/colorAccent"
    app:tabGravity="fill"
    app:tabMode="scrollable"/>

This will set background to behind tabLayout instead of setting background behind every tab.

Solution 4

Here is my 2021 Kotlin solution. It achieves the following which I couldn't do from other answers:

  • If not many tabs they expand to fill the whole width.
  • If lots of tabs they are scrollable so they aren't squished.
  • Works correctly even if tabLayout is not the full width of the screen.

To achieve this I created a subclass of TabLayout that overrides onMeasure

class ScalableTabLayout : TabLayout {
    constructor(context: Context) : super(context)
    constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(
        context,
        attrs,
        defStyleAttr
    )

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        val tabLayout = getChildAt(0) as ViewGroup
        val childCount = tabLayout.childCount
        if (childCount > 0) {
            val widthPixels = MeasureSpec.getSize(widthMeasureSpec)
            val tabMinWidth = widthPixels / childCount
            var remainderPixels = widthPixels % childCount
            tabLayout.forEachChild {
                if (remainderPixels > 0) {
                    it.minimumWidth = tabMinWidth + 1
                    remainderPixels--
                } else {
                    it.minimumWidth = tabMinWidth
                }
            }
        }
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
    }
}

And then used it in my layout file:

<com.package.name.ScalableTabLayout
    android:id="@+id/tabs"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:tabMaxWidth="0dp"
    app:tabMode="scrollable" />

both tabMaxWidth="0dp" and tabMode="scrollable" are required

Solution 5

please use this it will solve this problem definitely

<android.support.design.widget.TabLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:tabMaxWidth="0dp"
        app:tabGravity="fill"
        app:tabMode="fixed" />
Share:
59,074
Sufian
Author by

Sufian

Android application developer with 8+ years of experience. Personal works: Simple Material Library - allows developers to integrated Raised and Flat buttons in their Android applications. The Art of War - an e-book of the famous treatise by Sun Tzu. Bane SMS - an application which allows users to manage their SMS, such as search, delete, favourite, etc. Constraint Layout Tutorial - demo with the presentation slides about the introduction of code features of the Constraint Layout.

Updated on April 09, 2021

Comments

  • Sufian
    Sufian about 3 years

    I have added TabLayout (from support library v22.2.1) to my Fragment as:

    <android.support.design.widget.TabLayout
            android:id="@+id/tabs"
            style="@style/MyColorAccentTabLayout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:tabMode="scrollable"/>
    

    The issue is that when the Fragment's orientation is landscape (before or after the initial creation of the fragment), the TabLayout doesn't match the width of the Fragment (yes the parent has its width set to match_parent as well).

    When screen width is small (i.e not all tabs can be shown at same time): enter image description here

    When screen width is big enough to show all tabs (see the blank space at the right): enter image description here

    If I change tabMode to fixed, width is filled but tabs are too small. Is there any proper solution out there?