Android Support Design TabLayout: Центр гравитации и режим прокрутки
Я пытаюсь использовать новый проект TabLayout в своем проекте. Я хочу, чтобы макет адаптировался к каждому размеру экрана и ориентации, но его можно увидеть правильно в одной ориентации.
Я имею дело с Gravity и Mode, устанавливая мой tabLayout как:
tabLayout.setTabGravity(TabLayout.GRAVITY_CENTER);
tabLayout.setTabMode(TabLayout.MODE_SCROLLABLE);
Поэтому я ожидаю, что если нет места, tabLayout прокручивается, но если есть место, оно центрируется.
Из руководств:
public static final int GRAVITY_CENTER Гравитация, используемая для выкладки вкладки в центре TabLayout.
public static final int GRAVITY_FILL Гравитация, используемая для заполнения TabLayout как можно больше. Эта опция действует только тогда, когда используется с MODE_FIXED.
public static final int MODE_FIXED Фиксированные вкладки отображают все вкладки одновременно и лучше всего использовать с контентом, который поворот между вкладками. Максимальное количество вкладок ограничено ширина просмотров. Фиксированные вкладки имеют равную ширину, основанную на самой широкой вкладке метка.
public static final int MODE_SCROLLABLE Прокручиваемые вкладки отображают подмножество вкладок в любой момент времени и может содержать более длинные метки ярлыков и большее количество вкладок. Они лучше всего подходят для просмотра контекстов в сенсорных интерфейсах, когда пользователям не нужно напрямую сравнивать вкладку метки.
Итак, GRAVITY_FILL совместим только с MODE_FIXED, но в at ничего не указывается для GRAVITY_CENTER, я ожидаю, что он будет совместим с MODE_SCROLLABLE, но это то, что я получаю от использования GRAVITY_CENTER и MODE_SCROLLABLE
![enter image description here]()
Таким образом, он использует SCROLLABLE в обеих ориентациях, но не использует GRAVITY_CENTER.
Это то, что я ожидал бы от пейзажа; но для этого мне нужно установить MODE_FIXED, так что я получаю в портрете:
![enter image description here]()
Почему GRAVITY_CENTER не работает для SCROLLABLE, если tabLayout подходит для экрана?
Есть ли способ установить гравитацию и режим динамически (и посмотреть, что я ожидаю)?
Большое спасибо!
EDITED: это макет моей вкладки TabLayout:
<android.support.design.widget.TabLayout
android:id="@+id/sliding_tabs"
android:layout_width="match_parent"
android:background="@color/orange_pager"
android:layout_height="wrap_content" />
Ответы
Ответ 1
Поскольку я не нашел, почему это происходит, я использовал следующий код:
float myTabLayoutSize = 360;
if (DeviceInfo.getWidthDP(this) >= myTabLayoutSize ){
tabLayout.setTabMode(TabLayout.MODE_FIXED);
} else {
tabLayout.setTabMode(TabLayout.MODE_SCROLLABLE);
}
В принципе, мне приходится вручную вычислять ширину моего tabLayout, а затем я устанавливаю режим Tab в зависимости от того, подходит ли tabLayout на устройстве или нет.
Причина, по которой я получаю размер макета вручную, заключается в том, что не все вкладки имеют одинаковую ширину в режиме прокрутки, и это может спровоцировать, что некоторые имена используют 2 строки, как это случилось со мной в этом примере.
Ответ 2
Эффекты только для гравитации таблеток MODE_FIXED
.
Одно из возможных решений - установить layout_width
на wrap_content
и layout_gravity
на center_horizontal
:
<android.support.design.widget.TabLayout
android:id="@+id/sliding_tabs"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
app:tabMode="scrollable" />
Если вкладки меньше ширины экрана, сам TabLayout
также будет меньше, и он будет центрирован из-за силы тяжести. Если вкладки больше ширины экрана, TabLayout
будет соответствовать ширине экрана, и прокрутка активируется.
Ответ 3
вот как я это сделал
TabLayout.xml
<android.support.design.widget.TabLayout
android:id="@+id/tab_layout"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:background="@android:color/transparent"
app:tabGravity="fill"
app:tabMode="scrollable"
app:tabTextAppearance="@style/TextAppearance.Design.Tab"
app:tabSelectedTextColor="@color/myPrimaryColor"
app:tabIndicatorColor="@color/myPrimaryColor"
android:overScrollMode="never"
/>
OnCreate
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mToolbar = (Toolbar) findViewById(R.id.toolbar_actionbar);
mTabLayout = (TabLayout)findViewById(R.id.tab_layout);
mTabLayout.setOnTabSelectedListener(this);
setSupportActionBar(mToolbar);
mTabLayout.addTab(mTabLayout.newTab().setText("Dashboard"));
mTabLayout.addTab(mTabLayout.newTab().setText("Signature"));
mTabLayout.addTab(mTabLayout.newTab().setText("Booking/Sampling"));
mTabLayout.addTab(mTabLayout.newTab().setText("Calendar"));
mTabLayout.addTab(mTabLayout.newTab().setText("Customer Detail"));
mTabLayout.post(mTabLayout_config);
}
Runnable mTabLayout_config = new Runnable()
{
@Override
public void run()
{
if(mTabLayout.getWidth() < MainActivity.this.getResources().getDisplayMetrics().widthPixels)
{
mTabLayout.setTabMode(TabLayout.MODE_FIXED);
ViewGroup.LayoutParams mParams = mTabLayout.getLayoutParams();
mParams.width = ViewGroup.LayoutParams.MATCH_PARENT;
mTabLayout.setLayoutParams(mParams);
}
else
{
mTabLayout.setTabMode(TabLayout.MODE_SCROLLABLE);
}
}
};
Я сделал небольшие изменения решения @Mario Velasco на выполняемой части
Ответ 4
Посмотрите android-tablayouthelper
Автоматически переключать TabLayout.MODE_FIXED и TabLayout.MODE_SCROLLABLE зависит от общей ширины табуляции.
Ответ 5
для простоты просто добавьте приложение: tabMode = "scrollable" и android: layout_gravity = "bottom"
именно так
<android.support.design.widget.TabLayout
android:id="@+id/tabs"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:layout_gravity="bottom"
app:tabMode="scrollable"
app:tabIndicatorColor="@color/colorAccent" />
![enter image description here]()
Ответ 6
Это решение, которое я использовал для автоматического изменения между SCROLLABLE
и FIXED
+ FILL
. Это полный код для решения @Fighter42:
(В приведенном ниже коде показано, где внести изменения, если вы использовали шаблон активности вкладки Google)
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
// Create the adapter that will return a fragment for each of the three
// primary sections of the activity.
mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
// Set up the ViewPager with the sections adapter.
mViewPager = (ViewPager) findViewById(R.id.container);
mViewPager.setAdapter(mSectionsPagerAdapter);
// Set up the tabs
final TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs);
tabLayout.setupWithViewPager(mViewPager);
// Mario Velasco code
tabLayout.post(new Runnable()
{
@Override
public void run()
{
int tabLayoutWidth = tabLayout.getWidth();
DisplayMetrics metrics = new DisplayMetrics();
ActivityMain.this.getWindowManager().getDefaultDisplay().getMetrics(metrics);
int deviceWidth = metrics.widthPixels;
if (tabLayoutWidth < deviceWidth)
{
tabLayout.setTabMode(TabLayout.MODE_FIXED);
tabLayout.setTabGravity(TabLayout.GRAVITY_FILL);
} else
{
tabLayout.setTabMode(TabLayout.MODE_SCROLLABLE);
}
}
});
}
Разметка:
<android.support.design.widget.TabLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal" />
Если вам не нужно заполнять ширину, лучше использовать решение @karaokyo.
Ответ 7
Для этого я создал класс AdaptiveTabLayout. Это был единственный способ найти решение проблемы, ответить на вопрос и избежать проблем/проблем, которые могут возникнуть в других ответах здесь.
Примечания:
- Обрабатывает макеты планшета/планшета.
- Обрабатывает случаи, когда их хватает
комната для
MODE_SCROLLABLE
, но недостаточно места для MODE_FIXED
. Если
вы не справитесь с этим случаем, это произойдет на некоторых устройствах, которые вы будете
см. различные размеры текста или духовки две строки текста на некоторых вкладках, которые
выглядит плохо.
- Он принимает реальные меры и не делает никаких предположений (например, экран имеет ширину 360dp или что-то еще...). Это работает с реальными размерами экрана и реальными размерами вкладок. Это означает, что он хорошо работает с переводами, потому что не предполагает размер табуляции, вкладки получают меру.
- Сделки с различными проходами на этапе onLayout, чтобы
избегайте дополнительной работы.
- Ширина макета должна быть
wrap_content
в xml. Не устанавливайте режим или гравитацию на xml.
AdaptiveTabLayout.java
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.design.widget.TabLayout;
import android.util.AttributeSet;
import android.widget.LinearLayout;
public class AdaptiveTabLayout extends TabLayout
{
private boolean mGravityAndModeSeUpNeeded = true;
public AdaptiveTabLayout(@NonNull final Context context)
{
this(context, null);
}
public AdaptiveTabLayout(@NonNull final Context context, @Nullable final AttributeSet attrs)
{
this(context, attrs, 0);
}
public AdaptiveTabLayout
(
@NonNull final Context context,
@Nullable final AttributeSet attrs,
final int defStyleAttr
)
{
super(context, attrs, defStyleAttr);
setTabMode(MODE_SCROLLABLE);
}
@Override
protected void onLayout(final boolean changed, final int l, final int t, final int r, final int b)
{
super.onLayout(changed, l, t, r, b);
if (mGravityAndModeSeUpNeeded)
{
setModeAndGravity();
}
}
private void setModeAndGravity()
{
final int tabCount = getTabCount();
final int screenWidth = UtilsDevice.getScreenWidth();
final int minWidthNeedForMixedMode = getMinSpaceNeededForFixedMode(tabCount);
if (minWidthNeedForMixedMode == 0)
{
return;
}
else if (minWidthNeedForMixedMode < screenWidth)
{
setTabMode(MODE_FIXED);
setTabGravity(UtilsDevice.isBigTablet() ? GRAVITY_CENTER : GRAVITY_FILL) ;
}
else
{
setTabMode(TabLayout.MODE_SCROLLABLE);
}
setLayoutParams(new LinearLayout.LayoutParams
(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT));
mGravityAndModeSeUpNeeded = false;
}
private int getMinSpaceNeededForFixedMode(final int tabCount)
{
final LinearLayout linearLayout = (LinearLayout) getChildAt(0);
int widestTab = 0;
int currentWidth;
for (int i = 0; i < tabCount; i++)
{
currentWidth = linearLayout.getChildAt(i).getWidth();
if (currentWidth == 0) return 0;
if (currentWidth > widestTab)
{
widestTab = currentWidth;
}
}
return widestTab * tabCount;
}
}
И это класс DeviceUtils:
import android.content.res.Resources;
public class UtilsDevice extends Utils
{
private static final int sWIDTH_FOR_BIG_TABLET_IN_DP = 720;
private UtilsDevice() {}
public static int pixelToDp(final int pixels)
{
return (int) (pixels / Resources.getSystem().getDisplayMetrics().density);
}
public static int getScreenWidth()
{
return Resources
.getSystem()
.getDisplayMetrics()
.widthPixels;
}
public static boolean isBigTablet()
{
return pixelToDp(getScreenWidth()) >= sWIDTH_FOR_BIG_TABLET_IN_DP;
}
}
Пример использования:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.com.stackoverflow.example.AdaptiveTabLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="?colorPrimary"
app:tabIndicatorColor="@color/white"
app:tabSelectedTextColor="@color/text_white_primary"
app:tabTextColor="@color/text_white_secondary"
tools:layout_width="match_parent"/>
</FrameLayout>
Gist
Проблемы/Спросите о помощи:
Logcat:
W/View: requestLayout() improperly called by android.support.design.widget.TabLayout$SlidingTabStrip{3e1ebcd6 V.ED.... ......ID 0,0-466,96} during layout: running second layout pass
W/View: requestLayout() improperly called by android.support.design.widget.TabLayout$TabView{3423cb57 VFE...C. ..S...ID 0,0-144,96} during layout: running second layout pass
W/View: requestLayout() improperly called by android.support.design.widget.TabLayout$TabView{377c4644 VFE...C. ......ID 144,0-322,96} during layout: running second layout pass
W/View: requestLayout() improperly called by android.support.design.widget.TabLayout$TabView{19ead32d VFE...C. ......ID 322,0-466,96} during layout: running second layout pass
Я не уверен, как его решить. Любые предложения?
- Чтобы сделать дочерний элемент TabLayout, я делаю некоторые кастинги и предположения (Подобно ребенку LinearLayout, содержащему другие представления...)
Это может вызвать проблемы с дальнейшими обновлениями библиотеки технической поддержки. Лучший подход/предложения?
Ответ 8
Это единственный код, который работал у меня:
public static void adjustTabLayoutBounds(final TabLayout tabLayout,
final DisplayMetrics displayMetrics){
final ViewTreeObserver vto = tabLayout.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
tabLayout.getViewTreeObserver().removeOnGlobalLayoutListener(this);
int totalTabPaddingPlusWidth = 0;
for(int i=0; i < tabLayout.getTabCount(); i++){
final LinearLayout tabView = ((LinearLayout)((LinearLayout) tabLayout.getChildAt(0)).getChildAt(i));
totalTabPaddingPlusWidth += (tabView.getMeasuredWidth() + tabView.getPaddingLeft() + tabView.getPaddingRight());
}
if (totalTabPaddingPlusWidth <= displayMetrics.widthPixels){
tabLayout.setTabMode(TabLayout.MODE_FIXED);
tabLayout.setTabGravity(TabLayout.GRAVITY_FILL);
}else{
tabLayout.setTabMode(TabLayout.MODE_SCROLLABLE);
}
tabLayout.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT));
}
});
}
Экземпляр DisplayMetrics можно получить, используя следующую команду:
public DisplayMetrics getDisplayMetrics() {
final WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
final Display display = wm.getDefaultDisplay();
final DisplayMetrics displayMetrics = new DisplayMetrics();
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
display.getMetrics(displayMetrics);
}else{
display.getRealMetrics(displayMetrics);
}
return displayMetrics;
}
И ваш XML файл TabLayout должен выглядеть так (не забудьте установить tabMaxWidth равным 0):
<android.support.design.widget.TabLayout
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/tab_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:tabMaxWidth="0dp"/>
Ответ 9
Все, что вам нужно, - добавить в свой TabLayout следующее:
custom:tabGravity="fill"
Итак, у вас будет:
xmlns:custom="http://schemas.android.com/apk/res-auto"
<android.support.design.widget.TabLayout
android:id="@+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
custom:tabGravity="fill"
/>
Ответ 10
Я решил это, используя следующие
if(tabLayout_chemistCategory.getTabCount()<4)
{
tabLayout_chemistCategory.setTabGravity(TabLayout.GRAVITY_FILL);
}else
{
tabLayout_chemistCategory.setTabMode(TabLayout.MODE_SCROLLABLE);
}
Ответ 11
<android.support.design.widget.TabLayout
android:id="@+id/tabList"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
app:tabMode="scrollable"/>
Ответ 12
Очень простой пример, и он всегда работает.
/**
* Setup stretch and scrollable TabLayout.
* The TabLayout initial parameters in layout must be:
* android:layout_width="wrap_content"
* app:tabMaxWidth="0dp"
* app:tabGravity="fill"
* app:tabMode="fixed"
*
* @param context your Context
* @param tabLayout your TabLayout
*/
public static void setupStretchTabLayout(Context context, TabLayout tabLayout) {
tabLayout.post(() -> {
ViewGroup.LayoutParams params = tabLayout.getLayoutParams();
if (params.width == ViewGroup.LayoutParams.MATCH_PARENT) { // is already set up for stretch
return;
}
int deviceWidth = context.getResources()
.getDisplayMetrics().widthPixels;
if (tabLayout.getWidth() < deviceWidth) {
tabLayout.setTabMode(TabLayout.MODE_FIXED);
params.width = ViewGroup.LayoutParams.MATCH_PARENT;
} else {
tabLayout.setTabMode(TabLayout.MODE_SCROLLABLE);
params.width = ViewGroup.LayoutParams.WRAP_CONTENT;
}
tabLayout.setLayoutParams(params);
});
}
Ответ 13
Мое окончательное решение
class DynamicModeTabLayout : 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 setupWithViewPager(viewPager: ViewPager?) {
super.setupWithViewPager(viewPager)
val view = getChildAt(0) ?: return
view.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED)
val size = view.measuredWidth
if (size > measuredWidth) {
tabMode = MODE_SCROLLABLE
tabGravity = GRAVITY_CENTER
} else {
tabMode = MODE_FIXED
tabGravity = GRAVITY_FILL
}
}
}