Android Support Design TabLayout: Centro de Gravedad y Modo Scrollable

Estoy intentando utilizar el nuevo diseño TabLayout en mi proyecto. Quiero que el diseño se adapte a cada tamaño de pantalla y orientación, pero se puede ver correctamente en una orientación.

Estoy tratando con Gravity y Mode configurando mi tabLayout como:

tabLayout.setTabGravity(TabLayout.GRAVITY_CENTER); tabLayout.setTabMode(TabLayout.MODE_SCROLLABLE); 

Así que espero que si no hay espacio, el tabLayout es desplazable, pero si hay espacio, se centra.

De las guías:

Public static final int GRAVITY_CENTER Gravedad utilizada para establecer las pestañas en el centro de TabLayout.

Public static final int GRAVITY_FILL Gravedad utilizada para llenar el TabLayout tanto como sea posible. Esta opción sólo tiene efecto cuando se utiliza con MODE_FIXED.

Public static final int MODE_FIXED Las pestañas fijas muestran todas las pestañas simultáneamente y se utilizan mejor con contenido que se beneficia de pivotes rápidos entre pestañas. El número máximo de pestañas está limitado por el ancho de la vista. Las pestañas fijas tienen el mismo ancho, basado en la etiqueta de pestaña más amplia.

Public static final int MODE_SCROLLABLE Las pestañas desplegables muestran un subconjunto de pestañas en un momento dado y pueden contener etiquetas de pestañas más largas y un mayor número de pestañas. Se utilizan mejor para contextos de navegación en interfaces táctiles cuando los usuarios no necesitan comparar directamente las etiquetas de pestaña.

Así GRAVITY_FILL es compatible sólo con MODE_FIXED pero, en es no especifica nada para GRAVITY_CENTER, espero que sea compatible con MODE_SCROLLABLE, pero esto es lo que obtengo usando GRAVITY_CENTER y MODE_SCROLLABLE

Introduzca aquí la descripción de la imagen

Por lo tanto, está utilizando SCROLLABLE en ambas orientaciones, pero no utiliza GRAVITY_CENTER.

Esto es lo que yo esperaría para el paisaje; Pero para tener esto, necesito fijar MODE_FIXED, así que lo que consigo en retrato es:

Introduzca aquí la descripción de la imagen

¿Por qué GRAVITY_CENTER no funciona para SCROLLABLE si el tabLayout se ajusta a la pantalla? ¿Hay alguna manera de establecer la gravedad y el modo de forma dinámica (y ver lo que estoy esperando)?

¡Muchas gracias!

EDITED: Este es el Layout de mi 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 Solutions collect form web for “Android Support Design TabLayout: Centro de Gravedad y Modo Scrollable”

La gravedad de la pestaña sólo tiene efectos MODE_FIXED .

Una solución posible es establecer su layout_width a wrap_content y layout_gravity a 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" /> 

Si las pestañas son más pequeñas que el ancho de la pantalla, TabLayout también será más pequeño y se centrará debido a la gravedad. Si las pestañas son mayores que el ancho de la pantalla, TabLayout coincidirá con el ancho de la pantalla y se activará el desplazamiento.

Así es como lo hice

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

Crecer

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

Hice pequeños cambios en la solución de @Mario Velasco en la parte ejecutable

Mira android-tablayouthelper

Cambiar automáticamente TabLayout.MODE_FIXED y TabLayout.MODE_SCROLLABLE depende del ancho total de la pestaña.

Mantiene las cosas simples solo agrega app: tabMode = "scrollable" and android: layout_gravity = "bottom"

Así como esto

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

Introduzca aquí la descripción de la imagen

Esta es la solución que usé para cambiar automáticamente entre SCROLLABLE y FIXED + FILL . Es el código completo para la solución @ Fighter42:

(El código siguiente muestra dónde colocar la modificación si ha utilizado la plantilla de actividad de pestañas de 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); } } }); } 

Diseño:

  <android.support.design.widget.TabLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" /> 

Si no necesita rellenar el ancho, mejor utilizar la solución @karaokyo.

Todo lo que necesitas es agregar lo siguiente a tu TabLayout

 custom:tabGravity="fill" 

Entonces tendrás:

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

Como no he encontrado por qué ocurre este comportamiento he utilizado el código siguiente:

 float myTabLayoutSize = 360; if (DeviceInfo.getWidthDP(this) >= myTabLayoutSize ){ tabLayout.setTabMode(TabLayout.MODE_FIXED); } else { tabLayout.setTabMode(TabLayout.MODE_SCROLLABLE); } 

Básicamente, tengo que calcular manualmente el ancho de mi tabLayout y luego establecer el modo de ficha dependiendo de si el tabLayout se ajusta en el dispositivo o no.

La razón por la que obtengo el tamaño del diseño manualmente es porque no todas las pestañas tienen el mismo ancho en modo Scrollable, y esto podría provocar que algunos nombres usen 2 líneas como me pasó en el ejemplo.

Este es el único código que funcionó para mí:

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

El DisplayMetrics se puede recuperar utilizando esto:

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

Y su TabLayout XML debería tener este aspecto (no olvide establecer tabMaxWidth en 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"/> 

He creado una clase AdaptiveTabLayout para lograr esto. Esta fue la única manera que encontré para resolver el problema, responder a la pregunta y evitar / problemas de solución que otras respuestas aquí no.

Notas:

  • Maneja los diseños de teléfono / tableta.
  • Maneja casos donde hay suficiente espacio para MODE_SCROLLABLE pero no suficiente espacio para MODE_FIXED . Si no manejas este caso, sucederá en algunos dispositivos que verás diferentes tamaños de texto o horno dos líneas de texto en algunas pestañas, que se ve mal.
  • Obtiene medidas reales y no hace ninguna suposición (como la pantalla es de 360dp de ancho o lo que sea …). Esto funciona con tamaños de pantalla reales y tamaños de tabulación reales. Esto significa que funciona bien con las traducciones, ya que no asume ningún tamaño de tabulación, las pestañas obtener medida.
  • Trata con los diferentes pases en la fase onLayout para evitar trabajo extra.
  • El ancho de diseño debe ser wrap_content en el xml. No establezca ningún modo o gravedad en el 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; } } 

Y esta es la clase 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; } } 

Ejemplo de uso:

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

Esencia

Problemas / Pida ayuda:

  • Usted verá esto:

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 

No estoy seguro de cómo solucionarlo. ¿Alguna sugerencia?

  • Para hacer que el niño de TabLayout mida, estoy haciendo algunos castings y suposiciones (como el niño es un LinearLayout que contiene otras vistas ….) Esto podría causar problemas en las nuevas actualizaciones de la biblioteca de soporte de diseño. Un mejor enfoque / sugerencias?

He resuelto esto usando los siguientes

 if(tabLayout_chemistCategory.getTabCount()<4) { tabLayout_chemistCategory.setTabGravity(TabLayout.GRAVITY_FILL); }else { tabLayout_chemistCategory.setTabMode(TabLayout.MODE_SCROLLABLE); } 
  • Elementos compartidos de Android con Picasso
  • ¿Cómo cambiar la dirección de los iconos para los elementos del menú en un NavigationView?
  • Fuente personalizada para el mensaje de error de TextInputLayout en android
  • Alternativa a registerDataSetObserver () en RecyclerView
  • Reemplazar el diseño de la barra de herramientas de acuerdo con el fragmento visualizado
  • Android L - Botón de acción flotante (FAB)
  • Desactivar la hamburguesa para animar la flecha hacia atrás en la barra de herramientas
  • Cómo cambiar el color de la barra de herramientas y los colores de la barra de estado de acuerdo con el color de la imagen en el diseño de material android?
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.