当 tabMode 设置为“可滚动”时,TabLayout 不填充宽度

Posted

技术标签:

【中文标题】当 tabMode 设置为“可滚动”时,TabLayout 不填充宽度【英文标题】:TabLayout not filling width when tabMode set to 'scrollable' 【发布时间】:2015-12-12 14:46:59 【问题描述】:

我已将TabLayout(来自支持库 v22.2.1)添加到我的片段中:

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

问题是当片段的方向是横向时(在片段初始创建之前或之后),TabLayoutFragment 的宽度不匹配(是的,父级的宽度设置为@ 987654331@也一样)。

当屏幕宽度较小时(即不能同时显示所有选项卡):

当屏幕宽度足够大以显示所有选项卡时(请参阅右侧的空白区域):

如果我将tabMode 更改为固定,则宽度已填充但选项卡太小。有没有合适的解决方案?

【问题讨论】:

看看这个线程:***.com/questions/31698756/…,也看看这个:code.google.com/p/android/issues/detail?id=175516(仍然没有修复 imo) 【参考方案1】:

我想这是实现你想要的最简单的方法。

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

【讨论】:

太棒了!抱歉耽搁了。我忙于其他事情,所以我无法测试这个。我认为谷歌应该解决这个问题。我很惊讶他们如何允许半生不熟的东西出来。 mTabMinWidth 在设计支持库版本 23.1.1 上不存在 在新的支持库中,它被称为“mScrollableTabMinWidth” 在 28.0.0 中它的'scrollableTabMinWidth' 我必须在 layout.xml 中将 tabMode 定义为 'fixed' 并且还需要添加 'setTabMode(MODE_SCROLLABLE);'在 onMeasure 结束时。 (因为 TabLayout 在模式之间切换时会重新计算其选项卡。仅更改可滚动选项卡的宽度并不会使其重新计算选项卡。【参考方案2】:

试试这个改动

 <android.support.design.widget.TabLayout
        android:id="@+id/sliding_tabs"
        android:layout_
        android:layout_
        app:tabMode="fixed"
        app:tabGravity="fill" />

【讨论】:

请再次阅读我的问题。我已经提到我已经尝试过了。 固定屏幕宽度时标签会变小 我刚刚对这个答案投了赞成票,但在我的情况下,我从两个选项卡开始,固定模式可以根据需要将它们拉伸并居中。然后我在应用会话期间动态添加更多选项卡,然后我以编程方式将模式更改为可滚动。 添加 app:tabGravity="fill" 对我有用,因为我想拥有最多 3 个标签的固定模式【参考方案3】:

我不关心标签填充宽度,但我关心背景颜色没有扩展到整个宽度。所以我想到了这个解决方案,我在它后面放了一个与标签相同的背景颜色的 FrameLayout。

<FrameLayout
    android:layout_
    android:layout_
    android:background="@color/MyColor">
    <android.support.design.widget.TabLayout
        android:id="@+id/tabs"
        style="@style/MyCustomTabLayout"
        android:layout_
        android:layout_
        app:tabMode="scrollable"/>
</FrameLayout>

【讨论】:

【参考方案4】:

而不是创建自定义 TabLayout 和修改或创建更多的布局,这些布局仅作为背景的 TabLayout 的包装器。试试这个,

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

这会将背景设置在 tabLayout 后面,而不是在每个选项卡后面设置背景。

【讨论】:

【参考方案5】:

如果任何选项卡标题大于 (measuredWidth/tabCount),@dtx12 答案将不起作用。

我的 TabLayout 子类适用于这种情况(在 Kotlin 中)。我希望这会对某人有所帮助。

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()
                
            
        
    

【讨论】:

我遇到了类似的问题,Kotlin 也帮不上忙——开发人员使用 Java。当只有少数开发人员真正在商业产品中使用这些语言时,这就像在 Scala 或 Groovy 中提供解决方案一样。【参考方案6】:

请用这个绝对可以解决这个问题

<android.support.design.widget.TabLayout
        android:layout_
        android:layout_
        app:tabMaxWidth="0dp"
        app:tabGravity="fill"
        app:tabMode="fixed" />

【讨论】:

这绝对是最好的解决方案,如果没有“tabMaxWidth="0dp"”,该解决方案不适用于三星 Tab4 等某些设备。所以这对我来说是最好的解决方案。谢谢。 也适合我。【参考方案7】:

请检查一下我认为它有效

公共类 MainActivity 扩展 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_
    android:layout_
    android:layout_weight="0"
    android:fillViewport="true"
    android:measureAllChildren="false"
    android:scrollbars="none" >
    <LinearLayout
        android:id="@+id/innerLay"
        android:layout_
        android:layout_
        android:orientation="horizontal" >
        <LinearLayout
            android:layout_
            android:layout_
            android:orientation="vertical">

            <TextView
                android:id="@+id/txv_home"
                android:layout_
                android:layout_
                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_
                android:layout_
                android:background="@color/colorPrimary"
               />
        </LinearLayout>
        <View
            android:layout_
            android:layout_
            android:visibility="gone"
            android:background="#e8e8e8"/>
        <LinearLayout
            android:layout_
            android:layout_
            android:orientation="vertical">

            <TextView
                android:id="@+id/txv_news"
                android:layout_
                android:layout_
                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_
                android:layout_
                android:background="#e8e8e8"/>
        </LinearLayout>
        <View
            android:layout_
            android:layout_
            android:visibility="gone"
            android:background="#e8e8e8"/>
        <LinearLayout
            android:layout_
            android:layout_
            android:orientation="vertical">

            <TextView
                android:id="@+id/txv_announcements"
                android:layout_
                android:layout_
                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_
                android:layout_
                android:background="#e8e8e8"/>
        </LinearLayout>

    </LinearLayout>
</HorizontalScrollView>
<android.support.v4.view.ViewPager
    android:id="@+id/viewpager"
    android:layout_
    android:layout_
    android:layout_below="@+id/hsv" />

【讨论】:

【参考方案8】:

androidx 版本:

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

***** 下面是旧答案 *****

试试这个,这是一种设置tabMaxWidth="0dp"tabGravity="fill"tabMode="fixed"的解决方法。

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

10 英寸平板电脑上的屏幕截图:

【讨论】:

你让我开心...谢谢 此解决方案不适合动态选项卡数,比如超过 5 个,因为它的 tabMode 是固定的 这不是问题的解决方案,因为当 tabMode 设置为“可滚动”时,作者要求填充宽度。在您的示例中,tabMode 设置为“固定” 请重新阅读问题,以及作者上传的截图。 你拯救了我的一天 app:tabMaxWidth=“0dp” 谢谢兄弟【参考方案9】:

当你想显示标签“填充”时,你应该设置 app:tabMode="fixed"。

**<android.support.design.widget.TabLayout
            android:id="@+id/tab_layout"
            android:layout_
            android:layout_
            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" />**

【讨论】:

【参考方案10】:

您可以在标签布局中使用 app:tabMaxWidth="0dp"

【讨论】:

【参考方案11】:

我也在苦苦挣扎,上面的大多数选项都不适合我,所以我根据 DTX12 的答案创建了一个版本。

我有一个布尔值来检查平板电脑与否,并检查横向和纵向。然后根据标签的数量设置布局。

您可能需要公开该方法并在轮换/配置更改时调用它。

在 CustomTabLayout 代码中我替换了 mintabswidth 方法

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



【讨论】:

【参考方案12】:

花了 2 天时间解决了这个问题,现在终于对我有用了。请参阅@Tyler V 的回答check here 来自 Tyler 的回答 '在调用 super.onMeasure() 之前设置最小宽度是关键。' 非常重要

【讨论】:

【参考方案13】:

此解决方案的工作原理是让 android 创建选项卡,然后计算它们的总宽度。然后检查选项卡是否适合屏幕宽度,如果适合则将 tabMode 设置为“固定”,这会缩放所有选项卡以适合屏幕宽度。

标签布局xml,父无关系:

<com.google.android.material.tabs.TabLayout
        android:id="@+id/tabs"
        android:layout_
        android:layout_
        app:tabMode="scrollable"/>

然后在您的活动中 onCreate 或片段 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

如果您将 TabLayout 与 Viewpager 一起使用,那么您必须设置一个 layoutChangeListener,因为选项卡在开始时不会膨胀。

在您的活动 onCreate 或片段 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
    

注意:如果您希望所有选项卡在 tabMode 为“固定”时具有相同的文本大小,那么您必须从 styles.xml 手动设置 textSize。

【讨论】:

【参考方案14】:
<android.support.design.widget.TabLayout
        android:id="@+id/tabs"
        android:layout_
        android:layout_
        android:layout_gravity="center"
        app:tabMode="scrollable"/>

【讨论】:

您必须将 layout_gravity 添加为 center 和 tabmode 可滚动 android:layout_gravity="center" 将标签标题垂直居中【参考方案15】:

这里有一个更简单的方法来确保标签的宽度等于标签的字符串长度

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

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

</androidx.viewpager.widget.ViewPager>

使用以下代码:-

app:tabMaxWidth="0dp"
app:tabMode="scrollable"

【讨论】:

【参考方案16】:

这是我将 tabMode 设置为的解决方案: 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)
  

【讨论】:

【参考方案17】:

我已经尝试了几乎所有的答案,最后发现这个很有魅力。

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;
        

【讨论】:

【参考方案18】:

这是我的 2021 Kotlin 解决方案。 它实现了我从其他答案中无法做到的以下几点:

如果选项卡不多,它们会展开以填满整个宽度。 如果有很多选项卡,它们是可滚动的,因此它们不会被压扁。 即使 tabLayout 不是屏幕的全宽也能正常工作。

为了实现这一点,我创建了一个 TabLayout 的子类,它覆盖了 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)
    

然后在我的布局文件中使用它:

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

tabMaxWidth="0dp"tabMode="scrollable" 都是必需的

【讨论】:

这是最好的解决方案!!谢谢! 这绝对是离合器,谢谢。请务必设置 app:tabPaddingEnd="0dp"app:tabPaddingStart="0dp" 否则您会在标签栏上看到一些来自未占像素的轻微时髦的滚动行为 @SameerJ 删除填充绝对不是我想要的。如果您像这样删除填充,则选项卡宽度只会包裹文本,因此所有选项卡将显示为一个连接。例如。三个选项卡“一”“二”“三”看起来像“OneTwoThree”。你指的是什么时髦的滚动? @MattSmith 从极左到极右选择选项卡时会发生一些抖动,因为选项卡布局的大小仍然比屏幕宽度大几个像素,因为 onMeasure 计算以上不考虑该填充

以上是关于当 tabMode 设置为“可滚动”时,TabLayout 不填充宽度的主要内容,如果未能解决你的问题,请参考以下文章

当我们将它的子项设置为列时,可拖动的可滚动工作表变得不可滚动

当方向是横向xcode时如何使屏幕可滚动

带有 UIButtons 的 UIScrollView - 当按钮开始触摸时,滚动视图不会滚动

在 Xcode 中根据设备的高度使页面可滚动

微信小程序之scroll-view可滚动视图区域

当softKeyBoard隐藏按钮和其他元素时如何使布局可滚动[ANDROID]