TabLayout not filling width when tabMode set to 'scrollable'
Asked Answered
D

19

61

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?

Declarant answered 16/9, 2015 at 6:42 Comment(1)
take a look at this thread: #31699256 and also a look at this one: code.google.com/p/android/issues/detail?id=175516 (still not fixed imo)Braunschweig
G
18

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();
        }
    }
}
Grieg answered 16/9, 2015 at 8:47 Comment(11)
Excellent! Sorry about the delay. I was busy with other things so I couldn't test this. I think Google should fix this issue. I am surprised how they allow half-baked things come out.Declarant
mTabMinWidth does not exist on design support library version 23.1.1Highroad
got java.lang.NoSuchFieldException: mTabMinWidthPredestinarian
use rKrishna's answer, this hack is not required anymoreGrieg
Everyone, please don't downvote the answer because this worked with the support lib 22.2.1 (please see the question). What makes sense is that you upvote other answers which work for you. It was Google who broke this solution, so the answer doesn't deserve downvotes!Declarant
In the new support library, its called "mScrollableTabMinWidth"Noel
Somehow, this is not working for me, can anyone please help... i am use the mScrollableTabMinWidth....Bristle
@Noel can you help me out please--- #39003184Bristle
I have the same issue, but the above answer didnt work for meAthelstan
In 28.0.0 its 'scrollableTabMinWidth'Margenemargent
I had to define the tabMode as 'fixed' in the layout.xml and also it was needed to add 'setTabMode(MODE_SCROLLABLE);' at the end of onMeasure. (Because TabLayout recalculates its tabs when changing between modes. Purely changing the scrollable tab widths didn't made it to recalculate the tabs.Grindstone
D
36

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

Dialyser answered 25/10, 2017 at 21:35 Comment(6)
You made my day...Thank youGunzburg
this solution doesn't fit for dynamic number of tabs, say more than 5, cause it's tabMode is fixedFalster
This is not solution to the question as author is asking to fill width when tabMode is set to "scrollable". In your example tabMode is set to "fixed"Diaphane
Please re-read the question, and the screenshots the author uploaded.Dialyser
you saved my day by app:tabMaxWidth=“0dp” thanks broMigrant
This approach is against material design principleVoguish
U
32

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.

Unpeopled answered 10/4, 2016 at 9:56 Comment(0)
G
18

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();
        }
    }
}
Grieg answered 16/9, 2015 at 8:47 Comment(11)
Excellent! Sorry about the delay. I was busy with other things so I couldn't test this. I think Google should fix this issue. I am surprised how they allow half-baked things come out.Declarant
mTabMinWidth does not exist on design support library version 23.1.1Highroad
got java.lang.NoSuchFieldException: mTabMinWidthPredestinarian
use rKrishna's answer, this hack is not required anymoreGrieg
Everyone, please don't downvote the answer because this worked with the support lib 22.2.1 (please see the question). What makes sense is that you upvote other answers which work for you. It was Google who broke this solution, so the answer doesn't deserve downvotes!Declarant
In the new support library, its called "mScrollableTabMinWidth"Noel
Somehow, this is not working for me, can anyone please help... i am use the mScrollableTabMinWidth....Bristle
@Noel can you help me out please--- #39003184Bristle
I have the same issue, but the above answer didnt work for meAthelstan
In 28.0.0 its 'scrollableTabMinWidth'Margenemargent
I had to define the tabMode as 'fixed' in the layout.xml and also it was needed to add 'setTabMode(MODE_SCROLLABLE);' at the end of onMeasure. (Because TabLayout recalculates its tabs when changing between modes. Purely changing the scrollable tab widths didn't made it to recalculate the tabs.Grindstone
S
8

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

Salicaceous answered 7/1, 2021 at 1:39 Comment(4)
This is the best solution!! Thanks!Douville
this is absolutely clutch, thanks. be sure to set app:tabPaddingEnd="0dp" and app:tabPaddingStart="0dp" otherwise you do see some slight funky scrolling behaviour on the tab bar from the unaccounted for pixelsToro
@SameerJ removing the padding is definitely not something I wanted. If you remove padding like that the tab width will only wrap the text so all tabs will appear connected as one. E.g. three tabs "One" "Two" "Three" will look like "OneTwoThree". What is the funky scrolling you're referring to?Salicaceous
@MattSmith there is some jitter that happens when selecting tabs from extreme left to extreme right, because the the size of the tab layout is still larger than the screen width by a few pixels, because the onMeasure calculation above doesn't account for that paddingToro
P
6

I have tried almost all answeres, atlast found this one works like a charm.

public void dynamicSetTabLayoutMode(TabLayout tabLayout) {
            int tabWidth = calculateTabWidth(tabLayout);
            int screenWidth =  getApplicationContext().getResources().getDisplayMetrics().widthPixels;
            if (tabWidth <= screenWidth) {
                tabLayout.setTabMode(TabLayout.MODE_FIXED);
            } else {
                tabLayout.setTabMode(TabLayout.MODE_SCROLLABLE);
            }
        }
    
      private int calculateTabWidth(TabLayout tabLayout) {
            int tabWidth = 0;
            for (int i = 0; i < tabLayout.getChildCount(); i++) {
                final View view = tabLayout.getChildAt(i);
                view.measure(0, 0); 
                tabWidth += view.getMeasuredWidth();
            }
            return tabWidth;
        }
Prothalamium answered 14/7, 2020 at 9:58 Comment(0)
E
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" />
Euboea answered 23/1, 2017 at 12:7 Comment(2)
definitely this is the best solution, without the "tabMaxWidth="0dp"" the solution not works on some devices like Samsung Tab4. So this is the very best solution for me. Thanks.Vansickle
Works for me, too.Paripinnate
U
2

This solution works by letting android create the tabs then calculating the total width of them. Then checks if the tabs will fit the screen width, if it will fit then sets the tabMode to "fixed" which scales all the tabs to fit the screen width.

The tab layout xml, parent doesn't matter:

<com.google.android.material.tabs.TabLayout
        android:id="@+id/tabs"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:tabMode="scrollable"/>

Then in your activity onCreate or fragment onCreateView:

var totalWidth = 0
var maxWidth = 0
for (i in 0 until tabLayout.tabCount) {
    val tabWidth = (tabLayout.getChildAt(0) as ViewGroup).getChildAt(i)!!.width
    totalWidth += tabWidth
    maxWidth = max(maxWidth, tabWidth)
}
val screenWidth = Resources.getSystem().displayMetrics.widthPixels

if (totalWidth <  screenWidth&& screenWidth/ tabLayout.tabCount >= maxWidth) {

    tabLayout.tabMode = TabLayout.MODE_FIXED
}

If you are using TabLayout with Viewpager, then you have to set a layoutChangeListener since the tabs are not inflated at the start.

In your activity onCreate or fragment onCreateView:

tabLayout.addOnLayoutChangeListener { _, _, _, _, _, _, _, _, _ ->
    var totalWidth = 0
    var maxWidth = 0
    for (i in 0 until tabLayout.tabCount) {
        val tabWidth = (tabLayout.getChildAt(0) as ViewGroup).getChildAt(i)!!.width
        totalWidth += tabWidth
        maxWidth = max(maxWidth, tabWidth)
    }

     val screenWidth = Resources.getSystem().displayMetrics.widthPixels

    if (totalWidth < screenWidth && screenWidth / tabLayout.tabCount >= maxWidth) {

        tabLayout.tabMode = TabLayout.MODE_FIXED
    }
}

Note: If you want all of your tabs to have same text size when the tabMode is "fixed", then you have to set the textSize manually from styles.xml.

Uro answered 24/7, 2019 at 11:19 Comment(0)
I
2

Here's an easier way to make sure that the width of tab is equal to tab's string length

<androidx.viewpager.widget.ViewPager
    android:id="@+id/vpTabs"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.google.android.material.tabs.TabLayout
        android:id="@+id/tabLayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:tabMaxWidth="0dp"
        app:tabMode="scrollable"/>

</androidx.viewpager.widget.ViewPager>

Tab length as big as String

Following code is used:-

app:tabMaxWidth="0dp"
app:tabMode="scrollable"
Internuncial answered 26/1, 2020 at 7:39 Comment(2)
this doesn't work with ViewPager2 [InflateException: Binary XML file line #16 in com.app:layout/fragment_categories: ViewPager2 does not support direct child views] :/Georgettageorgette
this is not working as setting tabMode to scrollable shift the tabTexts to the start and if texts are small then there will be empty space at the endSergei
D
1

try with this changes

 <android.support.design.widget.TabLayout
        android:id="@+id/sliding_tabs"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:tabMode="fixed"
        app:tabGravity="fill" />
Duley answered 16/9, 2015 at 9:40 Comment(4)
Please read my question again. I have mentioned that I already tried this.Declarant
tabs will be smaller when fixing the screen widthDuley
I just upvoted this answer, but in my case I start out with just two tabs and fixed mode works to stretch them out and center them as desired. I then add more tabs dynamically during the app session at which time I then change the mode programmatically to scrollable.Vig
Adding app:tabGravity="fill" worked for me as I wanted to have fixed mode for maximum 3 tabsMalt
B
0

I was struggling as well and most options above did not work for me, so I created a version on the answer of DTX12.

I have a boolean to check for tablet or not and make a check on landscape and portrait. Then set the layout based on amount of tabs.

You might need to make the method public and call it on rotation / configurationchange.

In the CustomTabLayout Code i replaced the mintabswidth method

private void initTabMinWidth()
{



    boolean isTablet = getContext().getResources().getBoolean(R.bool.device_is_tablet);
    boolean isLandscape = (wh[WIDTH_INDEX] > wh[HEIGHT_INDEX]) ? true : false;


    if (isTablet)
    {
        if (isLandscape)
        {
            if (this.getTabCount() > 8)
            {
                this.setTabGravity(TabLayout.GRAVITY_FILL);
                this.setTabMode(TabLayout.MODE_SCROLLABLE);
            } else
            {
                this.setTabGravity(TabLayout.GRAVITY_FILL);
                this.setTabMode(TabLayout.MODE_FIXED);
            }
        } else
        {
            if (this.getTabCount() > 6)
            {
                this.setTabGravity(TabLayout.GRAVITY_FILL);
                this.setTabMode(TabLayout.MODE_SCROLLABLE);
            } else
            {
                this.setTabGravity(TabLayout.GRAVITY_FILL);
                this.setTabMode(TabLayout.MODE_FIXED);
            }
        }
    } else
    {
        if (isLandscape)
        {
            if (this.getTabCount() > 6)
            {
                this.setTabGravity(TabLayout.GRAVITY_FILL);
                this.setTabMode(TabLayout.MODE_SCROLLABLE);
            } else
            {
                this.setTabGravity(TabLayout.GRAVITY_FILL);
                this.setTabMode(TabLayout.MODE_FIXED);
            }
        } else
        {
            if (this.getTabCount() > 4)
            {
                this.setTabGravity(TabLayout.GRAVITY_FILL);
                this.setTabMode(TabLayout.MODE_SCROLLABLE);
            } else
            {
                this.setTabGravity(TabLayout.GRAVITY_FILL);
                this.setTabMode(TabLayout.MODE_FIXED);
            }
        }
    }


}
Bullyboy answered 18/10, 2018 at 9:24 Comment(0)
M
0

After spending 2 days to figure out the issue, now finally it's working for me. Please see @Tyler V's answer check here From Tyler's answer 'It was key to set the minimum width before calling super.onMeasure().' is very important

Margenemargent answered 28/1, 2019 at 10:7 Comment(0)
O
0

This is my solution with tabMode set to: app:tabMode="scrollable"

class MyTabLayout(
  context: Context,
  attrs: AttributeSet?
) : TabLayout(context, attrs) {

  override fun onMeasure(
    widthMeasureSpec: Int,
    heightMeasureSpec: Int
  ) {

    val equalTabWidth= (MeasureSpec.getSize(widthMeasureSpec) / tabCount.toFloat()).toInt()

    for (index in 0..tabCount) {
      val tab = getTabAt(index)
      val tabMeasuredWidth = tab?.view?.measuredWidth ?: equalTabWidth

      if (tabMeasuredWidth < equalTabWidth) {
        tab?.view?.minimumWidth = equalTabWidth
      }
    }

    super.onMeasure(widthMeasureSpec, heightMeasureSpec)
  }
}
Osborn answered 25/3, 2020 at 16:58 Comment(0)
P
0

This method will work if you want to use it as scrollable tabs with custom tabs width

<com.google.android.material.tabs.TabLayout
        android:id="@+id/tabs"
        android:layout_width="match_parent"
        android:layout_height="48dp"
        app:tabMaxWidth="48dp"
        app:tabGravity="fill"
        app:tabMode="scrollable"/>
Pyrargyrite answered 14/3, 2022 at 11:34 Comment(0)
E
-1

Please check this i think it works

public class MainActivity extends AppCompatActivity {

private TextView mTxv_Home, mTxv_News, mTxv_Announcement;
private View mView_Home, mView_News, mView_Announcements;
private HorizontalScrollView hsv;
private ViewPager viewPager;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    mTxv_Home = (TextView) findViewById(R.id.txv_home);
    mTxv_News = (TextView) findViewById(R.id.txv_news);
    mTxv_Announcement = (TextView) findViewById(R.id.txv_announcements);
    mView_Home = (View) findViewById(R.id.view_home);
    mView_News = (View) findViewById(R.id.view_news);
    mView_Announcements = (View) findViewById(R.id.view_announcements);
    hsv = (HorizontalScrollView) findViewById(R.id.hsv);
    viewPager = (ViewPager) findViewById(R.id.viewpager);
    setupViewPager(viewPager);
    DisplayMetrics displaymetrics = new DisplayMetrics();
    getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
    int wt = displaymetrics.widthPixels/3;
    mTxv_Home.setWidth(wt);
    mTxv_News.setWidth(wt);
   // mTxv_Announcement.setWidth(wt);
    mTxv_Home.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {

            mTxv_Home.setTextColor(Color.parseColor("#3F51B5"));
            mTxv_News.setTextColor(Color.parseColor("#808080"));
            mTxv_Announcement.setTextColor(Color.parseColor("#808080"));
            mView_Home.setBackgroundColor(Color.parseColor("#3F51B5"));
            mView_News.setBackgroundColor(Color.parseColor("#E8E8E8"));
            mView_Announcements.setBackgroundColor(Color.parseColor("#E8E8E8"));
            hsv.post(new Runnable() {
                public void run() {
                    hsv.fullScroll(HorizontalScrollView.FOCUS_LEFT);
                }
            });
            viewPager.setCurrentItem(0);
        }
    });
    mTxv_News.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            mTxv_Home.setTextColor(Color.parseColor("#808080"));
            mTxv_News.setTextColor(Color.parseColor("#3F51B5"));
            mTxv_Announcement.setTextColor(Color.parseColor("#808080"));
            mView_Home.setBackgroundColor(Color.parseColor("#E8E8E8"));
            mView_News.setBackgroundColor(Color.parseColor("#3F51B5"));
            mView_Announcements.setBackgroundColor(Color.parseColor("#E8E8E8"));
            hsv.post(new Runnable() {
                public void run() {
                    int centerX = hsv.getChildAt(0).getWidth()/2;
                    hsv.scrollTo(centerX, 0);
                }
            });
            viewPager.setCurrentItem(1);


        }
    });
    mTxv_Announcement.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            mTxv_Home.setTextColor(Color.parseColor("#808080"));
            mTxv_News.setTextColor(Color.parseColor("#808080"));
            mTxv_Announcement.setTextColor(Color.parseColor("#3F51B5"));
            mView_Home.setBackgroundColor(Color.parseColor("#E8E8E8"));
            mView_News.setBackgroundColor(Color.parseColor("#E8E8E8"));
            mView_Announcements.setBackgroundColor(Color.parseColor("#3F51B5"));
            hsv.post(new Runnable() {
                public void run() {
                    hsv.fullScroll(HorizontalScrollView.FOCUS_RIGHT);
                }
            });
            viewPager.setCurrentItem(2);
        }
    });

    viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

        }

        @Override
        public void onPageSelected(int position) {

            if (position == 0) {
                mTxv_Home.setTextColor(Color.parseColor("#3F51B5"));
                mTxv_News.setTextColor(Color.parseColor("#808080"));
                mTxv_Announcement.setTextColor(Color.parseColor("#808080"));
                mView_Home.setBackgroundColor(Color.parseColor("#3F51B5"));
                mView_News.setBackgroundColor(Color.parseColor("#E8E8E8"));
                mView_Announcements.setBackgroundColor(Color.parseColor("#E8E8E8"));
                hsv.post(new Runnable() {
                    public void run() {
                        hsv.fullScroll(HorizontalScrollView.FOCUS_LEFT);
                    }
                });


            } else if (position == 1) {
                mTxv_Home.setTextColor(Color.parseColor("#808080"));
                mTxv_News.setTextColor(Color.parseColor("#3F51B5"));
                mTxv_Announcement.setTextColor(Color.parseColor("#808080"));
                mView_Home.setBackgroundColor(Color.parseColor("#E8E8E8"));
                mView_News.setBackgroundColor(Color.parseColor("#3F51B5"));
                mView_Announcements.setBackgroundColor(Color.parseColor("#E8E8E8"));
                hsv.post(new Runnable() {
                    public void run() {
                        int centerX = hsv.getChildAt(0).getWidth()/2;
                        hsv.scrollTo(centerX, 0);
                    }
                });


            } else if (position == 2) {
                mTxv_Home.setTextColor(Color.parseColor("#808080"));
                mTxv_News.setTextColor(Color.parseColor("#808080"));
                mTxv_Announcement.setTextColor(Color.parseColor("#3F51B5"));
                mView_Home.setBackgroundColor(Color.parseColor("#E8E8E8"));
                mView_News.setBackgroundColor(Color.parseColor("#E8E8E8"));
                mView_Announcements.setBackgroundColor(Color.parseColor("#3F51B5"));
                hsv.post(new Runnable() {
                    public void run() {
                        hsv.fullScroll(HorizontalScrollView.FOCUS_RIGHT);
                    }
                });
            }

        }
        @Override
        public void onPageScrollStateChanged(int state) {

        }
    });
}
private void setupViewPager(ViewPager viewPager) {
    ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager());
    adapter.addFragment(new HomeFragment(), "Home");
    adapter.addFragment(new NewsFragment(), "News");
    adapter.addFragment(new AnnouncementsFragment(), "Announcements");
    viewPager.setAdapter(adapter);
}

class ViewPagerAdapter extends FragmentPagerAdapter {
    private final List<Fragment> mFragmentList = new ArrayList<>();
    private final List<String> mFragmentTitleList = new ArrayList<>();

    public ViewPagerAdapter(FragmentManager manager) {
        super(manager);
    }

    @Override
    public Fragment getItem(int position) {
        return mFragmentList.get(position);
    }

    @Override
    public int getCount() {
        return mFragmentList.size();
    }

    public void addFragment(Fragment fragment, String title) {
        mFragmentList.add(fragment);
        mFragmentTitleList.add(title);
    }

    @Override
    public CharSequence getPageTitle(int position) {
        return mFragmentTitleList.get(position);
    }
}

}

<HorizontalScrollView
    android:id="@+id/hsv"
    android:layout_width="fill_parent"
    android:layout_height="56dp"
    android:layout_weight="0"
    android:fillViewport="true"
    android:measureAllChildren="false"
    android:scrollbars="none" >
    <LinearLayout
        android:id="@+id/innerLay"
        android:layout_width="fill_parent"
        android:layout_height="50dp"
        android:orientation="horizontal" >
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">

            <TextView
                android:id="@+id/txv_home"
                android:layout_width="wrap_content"
                android:layout_height="0dp"
                android:layout_weight="1"
                android:text="Home"
                android:singleLine="true"
                android:paddingLeft="35dp"
                android:paddingRight="35dp"
                android:gravity="center"
                android:textSize="15sp"/>
            <View
                android:id="@+id/view_home"
                android:layout_width="match_parent"
                android:layout_height="3dp"
                android:background="@color/colorPrimary"
               />
        </LinearLayout>
        <View
            android:layout_width="1dp"
            android:layout_height="match_parent"
            android:visibility="gone"
            android:background="#e8e8e8"/>
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">

            <TextView
                android:id="@+id/txv_news"
                android:layout_width="wrap_content"
                android:layout_height="0dp"
                android:layout_weight="1"
                android:text="News"
                android:singleLine="true"
                android:paddingLeft="35dp"
                android:paddingRight="35dp"
                android:gravity="center"
                android:textSize="15sp"/>
            <View
                android:id="@+id/view_news"
                android:layout_width="match_parent"
                android:layout_height="3dp"
                android:background="#e8e8e8"/>
        </LinearLayout>
        <View
            android:layout_width="1dp"
            android:layout_height="match_parent"
            android:visibility="gone"
            android:background="#e8e8e8"/>
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">

            <TextView
                android:id="@+id/txv_announcements"
                android:layout_width="wrap_content"
                android:layout_height="0dp"
                android:layout_weight="1"
                android:singleLine="true"
                android:text="Announcements"
                android:paddingLeft="35dp"
                android:paddingRight="35dp"
                android:gravity="center"
                android:textSize="15sp"/>
            <View
                android:id="@+id/view_announcements"
                android:layout_width="match_parent"
                android:layout_height="1dp"
                android:background="#e8e8e8"/>
        </LinearLayout>

    </LinearLayout>
</HorizontalScrollView>
<android.support.v4.view.ViewPager
    android:id="@+id/viewpager"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_below="@+id/hsv" />
Entryway answered 17/6, 2017 at 5:24 Comment(0)
P
-1

You should set app:tabMode="fixed" when you want to show tabs 'fill'.

**<android.support.design.widget.TabLayout
            android:id="@+id/tab_layout"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@+id/toolbar"
            android:background="#353535"
            app:tabMode="fixed"
            android:minHeight="?attr/actionBarSize"
            app:tabIndicatorColor="@color/red"
            android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />**
Planetstruck answered 17/11, 2017 at 8:21 Comment(0)
B
-1

You may used app:tabMaxWidth="0dp" in tablayout

Bridging answered 27/3, 2018 at 11:29 Comment(0)
K
-1
<android.support.design.widget.TabLayout
        android:id="@+id/tabs"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        app:tabMode="scrollable"/>
Klara answered 30/10, 2019 at 20:50 Comment(2)
you must add the layout_gravity as center and tabmode scrollableKlara
android:layout_gravity="center" will center the tab titles verticallyHamelin
L
-2

I didn't care about the tabs filling the width, but I cared that the background color wasn't expanding to the full width. So I thought of this solution, where I put a FrameLayout behind it with the same background color as the tabs.

<FrameLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@color/MyColor">
    <android.support.design.widget.TabLayout
        android:id="@+id/tabs"
        style="@style/MyCustomTabLayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:tabMode="scrollable"/>
</FrameLayout>
Lanate answered 20/1, 2016 at 1:8 Comment(0)
C
-2

@dtx12 answer doesn't work if any tab title is bigger than (measuredWidth/ tabCount).

There is my TabLayout subclass for this situation (in Kotlin). I hope this will help someone.

class FullWidthTabLayout : 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 onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
        super.onLayout(changed, l, t, r, b)
        if (changed) {
            val widths = mutableListOf<Int>()
            for (i in 0..this.tabCount - 1) {
                widths.add(this.getTabAt(i)!!.customView!!.width)
            }

            if (widths.sum() < this.measuredWidth) {
                var equalPart: Long = this.measuredWidth.toLong() / this.tabCount.toLong()
                var biggerWidths = widths.filter { it > equalPart }
                var smallerWidths = widths.filter { it <= equalPart }
                var rest: Long = this.measuredWidth.toLong() - biggerWidths.sum()
                while (biggerWidths.size != 0) {
                    equalPart = rest / smallerWidths.size
                    biggerWidths = smallerWidths.filter { it >= equalPart }
                    smallerWidths = smallerWidths.filter { it < equalPart }
                    rest -= biggerWidths.sum()
                }
                val minWidth = (rest / smallerWidths.size) + 10 //dont know why there is small gap on the end, thats why +10
                for (i in 0..this.tabCount - 1) {
                    this.getTabAt(i)!!.customView!!.minimumWidth = minWidth.toInt()
                }
            }
        }
    }
}
Cheat answered 29/9, 2016 at 13:11 Comment(1)
I had a similar issue and Kotlin won't help - devs use Java. It's like providing solution in Scala or Groovy when there are only a few devs that really use those languages in commercial products.Guessrope

© 2022 - 2024 — McMap. All rights reserved.