Подтвердить что ты не робот

TabLayout не заполняет ширину, когда tabMode установлен на "прокручиваемый"

Я добавил TabLayout (из библиотеки поддержки v22.2.1) в свой фрагмент как:

<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"/>

Проблема заключается в том, что когда ориентация фрагмента является альбомной (до или после первоначального создания фрагмента), TabLayout не соответствует ширине Fragment (да, родительский имеет ширину, установленную на match_parent).

Когда ширина экрана мала (то есть не все вкладки могут отображаться одновременно): введите описание изображения здесь

Когда ширина экрана достаточно велика, чтобы отобразить все вкладки (см. пустое пространство справа): введите описание изображения здесь

Если я изменю tabMode на фиксированный, ширина будет заполнена, но вкладки слишком малы. Есть ли там правильное решение?

4b9b3361

Ответ 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();
        }
    }
}

Ответ 2

Вместо создания пользовательского TabLayout и взлома или создания большего количества макетов, который действует как оболочка TabLayout только для фона. Попробуйте это,

<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"/>

Это установит фон для tabLayout вместо установки фона за каждой вкладкой.

Ответ 3

Попробуйте это, это обходной путь, который устанавливает tabMaxWidth="0dp", tabGravity="fill" и 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>

Снимок экрана на 10-дюймовом планшете:

screenshot

Ответ 4

пожалуйста, используйте это, он решит эту проблему определенно

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

Ответ 5

попробуйте с этими изменениями

 <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" />

Ответ 6

Я тоже боролся, и большинство вариантов, описанных выше, не помогли мне, поэтому я создал версию на ответ 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);
            }
        }
    }


}

Ответ 7

Потратив 2 дня, чтобы выяснить проблему, теперь, наконец, она работает для меня. Посмотрите, пожалуйста, проверку ответа @Tyler V здесь. От ответа Тайлера "Было важно установить минимальную ширину перед вызовом super.onMeasure()". очень важно

Ответ 8

просто сделайте это таким образом и добавьте app:tabMaxWidth="0dp" а также используйте app:tabGravity="fill"

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

Ответ 9

Это решение работает, позволяя Android создавать вкладки, а затем вычислять их общую ширину. Затем проверяет, будут ли вкладки соответствовать ширине экрана, если он будет соответствовать, затем устанавливает tabMode на "fixed", который масштабирует все вкладки, чтобы соответствовать ширине экрана.

Макет вкладки xml, родитель не имеет значения:

<com.google.android.material.tabs.TabLayout
        android:id="@+id/tabs"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        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 "фиксирован", то вам нужно установить textSize вручную из styles.xml.

Ответ 10

Мне не нравились вкладки, заполняющие ширину, но я думал, что цвет фона не расширяется до полной ширины. Поэтому я подумал об этом решении, где я поместил в него FrameLayout с тем же цветом фона, что и вкладки.

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

Ответ 11

Пожалуйста, проверьте это, я думаю, что он работает

открытый класс 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_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" />

Ответ 12

Вы должны установить приложение: tabMode = "fixed", если вы хотите отобразить вкладку tabs.

**<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" />**

Ответ 13

Вы можете использовать приложение: tabMaxWidth = "0dp" в tablayout

Ответ 14

@dtx12 ответ не работает, если заголовок табуляции больше, чем (measuredWidth/tabCount).

Для этой ситуации есть мой подкласс TabLayout (в Котлине). Надеюсь, это поможет кому-то.

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