Поддержка Android дизайн TabLayout: центр тяжести и режим прокрутки
Я пытаюсь использовать новый дизайн TabLayout в моем проекте. Я хочу, чтобы макет адаптировался к каждому размеру экрана и ориентации, но его можно правильно увидеть в одной ориентации.
Я имею дело с гравитацией и режим установки моего tabLayout как:
tabLayout.setTabGravity(TabLayout.GRAVITY_CENTER);
tabLayout.setTabMode(TabLayout.MODE_SCROLLABLE);
поэтому я ожидаю, что если нет места, tabLayout прокручивается, но если есть место, оно центрировано.
у гидов:
public static final int GRAVITY_CENTER Гравитация выложить вкладки в центре таблицы.
общедоступные статические заключительные инт GRAVITY_FILL тяжести, используемых для заполнения TabLayout как можно больше. Этот параметр вступает в силу только при использовании с MODE_FIXED.
public static final int MODE_FIXED фиксированные вкладки отображение всех вкладок одновременно и лучше всего использовать с контентом, который выигрывает от быстрого шарниры между вкладками. Максимальное количество вкладок ограничено ширина вида. Фиксированные вкладки имеют равная ширина, основанная на самой широкой вкладке этикетка.
общедоступные статические заключительные инт MODE_SCROLLABLE прокручивать вкладки отображения подмножество вкладок в любой момент времени, и может содержать более длинные метки вкладок и большее количество вкладок. Они лучше всего используются для просмотра контекстов в сенсорных интерфейсах, когда пользователям не нужно напрямую сравнивать вкладку ценник.
таким образом, GRAVITY_FILL совместим только с MODE_FIXED, но в is ничего не указывает для GRAVITY_CENTER, I ожидайте, что он будет совместим с MODE_SCROLLABLE, но это то, что я получаю с помощью GRAVITY_CENTER и MODE_SCROLLABLE
таким образом, он использует прокрутку в обеих ориентациях, но не использует GRAVITY_CENTER.
это то, что я ожидал бы для пейзажа; но чтобы иметь это, мне нужно установить MODE_FIXED, так что я получаю в портрете:
почему GRAVITY_CENTER не работает для прокрутки, если tabLayout соответствует экрану? Есть ли способ установить гравитацию и режим динамически (и посмотреть, что я ожидаю)?
большое спасибо!
отредактировано: это макет моего 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" />
10 ответов:
Tab gravity only effects
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
будет соответствовать ширине экрана и прокрутка активируется.
это, как я это сделал
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 на запускаемой части
посмотреть android-tablayouthelper
автоматическое переключение TabLayout.MODE_FIXED и TabLayout.MODE_SCROLLABLE зависит от общей ширины вкладки.
поскольку я не нашел, почему это происходит, я использовал следующий код:
float myTabLayoutSize = 360; if (DeviceInfo.getWidthDP(this) >= myTabLayoutSize ){ tabLayout.setTabMode(TabLayout.MODE_FIXED); } else { tabLayout.setTabMode(TabLayout.MODE_SCROLLABLE); }
в принципе, я должен вручную рассчитать ширину моего tabLayout, а затем установить режим вкладки в зависимости от того, подходит ли tabLayout к устройству или нет.
причина, по которой я получаю размер макета вручную, заключается в том, что не все вкладки имеют одинаковую ширину в режиме прокрутки, и это может спровоцировать то, что некоторые имена используют 2 строки, как это произошло со мной в образец.
держит вещи просто добавить приложение: tabMode= " прокрутка" и android: layout_gravity= "снизу"
просто так
<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" />
это решение, которое я использовал для автоматического изменения между
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's 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.
Я создал класс 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>
проблемы / обратиться за помощью:
- вы увидите это:
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, содержащий другие представления....) Это может вызвать проблемы с дальнейшими обновлениями библиотеки поддержки проектирования. Лучший подход / предложения?
все, что вам нужно, это добавить следующее в свой 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" />
Это единственный код, который работал для меня:
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; }
и ваш TabLayout XML должен выглядеть так (не забудьте установить 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"/>