material-components-android icon indicating copy to clipboard operation
material-components-android copied to clipboard

[TabLayout] Support gravity_fill with "auto" mode

Open firekesti opened this issue 4 years ago • 5 comments

Description: Setting the tabMode to auto is the same as setting the tabMode to scrollable. Even if there are only 2 items, they will never act like fixed tabs.

Expected behavior: Expected to act as in the documentation

Auto-sizing tabs behave like MODE_FIXED with GRAVITY_CENTER while the tabs fit within the TabLayout's content width. Fixed tabs have equal width, based on the widest tab label. Once the tabs outgrow the view's width, auto-sizing tabs behave like MODE_SCROLLABLE, allowing for a dynamic number of tabs without requiring additional layout logic.

Source code: By adding app:tabMode="auto" to the tab_layout view in component_tabs.xml and running the Material Theme Builder, you can see that the tabs no longer take up the full width of the parent. This occurs regardless of whether the parent is a LinearLayout or ConstraintLayout.

In updateTabViewLayoutParams in TabLayout, it sets the tabView layout params' width to WRAP_CONTENT if the mode is not MODE_FIXED, not sure if that's the issue.

Android API version: Seen on API 29.

Material Library version: Seen on alpha07, alpha09, and alpha10.

Device: Seen on Pixel 3 emulator.

firekesti avatar Oct 03 '19 20:10 firekesti

The documentation you cite matches the current behavior: Fixed tabs have equal width, based on the widest tab label

That's how gravity_center behaves vs gravity_fill which seems to be what you want. Let me know if you want to update this to a feature request or you could send us a pull request.

ymarian avatar Oct 04 '19 01:10 ymarian

Ahhhh thank you @ymarian , so if the tabMode is set to auto, then setting gravity_fill gets ignored? Thanks for clarifying! I was hoping it could work with gravity_fill - so it would automatically use the half-and-half setup for two tabs, third-third-third for three, and then if e.g. 6 tabs are added, it would go to the scrolling version. I will remove the bug label and read the docs more carefully :)

Edit: looks like I can't remove the bug label 😅

firekesti avatar Oct 04 '19 16:10 firekesti

Append the names of the tab in a list. So that you can do something like that: (getTabNameIds().size() < 3) ? TabLayout.MODE_FIXED : TabLayout.MODE_SCROLLABLE;

habibmax95 avatar Nov 18 '19 11:11 habibmax95

The source of this issue:

  private void updateTabViewLayoutParams(@NonNull LinearLayout.LayoutParams lp) {
    if (mode == MODE_FIXED && tabGravity == GRAVITY_FILL) {
      lp.width = 0;
      lp.weight = 1;
    } else {
      lp.width = LinearLayout.LayoutParams.WRAP_CONTENT;
      lp.weight = 0;
    }
  }

Shouldn't it be as simple as removing the mode check? If the user requested gravity=fill, then weight=1 should be applied regardless of mode.

jhansche avatar Nov 14 '22 18:11 jhansche

The source of this issue:

  private void updateTabViewLayoutParams(@NonNull LinearLayout.LayoutParams lp) {
    if (mode == MODE_FIXED && tabGravity == GRAVITY_FILL) {
      lp.width = 0;
      lp.weight = 1;
    } else {
      lp.width = LinearLayout.LayoutParams.WRAP_CONTENT;
      lp.weight = 0;
    }
  }

Shouldn't it be as simple as removing the mode check? If the user requested gravity=fill, then weight=1 should be applied regardless of mode.

I think so too. The introduction of a boolean type parameter, such as tabModeAutoFillWidth, would likely be for the purpose of configuring a user interface element in a software application. For instance, if you're referring to tabs in a tab bar or a navigation component, this parameter could control whether the tabs automatically resize to fill the available width.

Here’s how such a parameter might be used in different contexts:

    private void updateTabViewLayoutParams(@NonNull LinearLayout.LayoutParams lp) {
        if (mode == MODE_FIXED && tabGravity == GRAVITY_FILL) {
            lp.width = 0;
            lp.weight = 1;
        } else if (tabModeAutoFillWidth && mode == MODE_AUTO && tabGravity == GRAVITY_FILL) {
            lp.width = LinearLayout.LayoutParams.WRAP_CONTENT;
            lp.weight = 1;
        } else {
            lp.width = LinearLayout.LayoutParams.WRAP_CONTENT;
            lp.weight = 0;
        }
    }

kingwang666 avatar Jan 19 '24 11:01 kingwang666