J'essaie d'utiliser le nouveau Design TabLayout dans mon projet. Je veux que la disposition s'adapte à toutes les tailles et orientations d'écran, mais elle peut être vue correctement dans une orientation.
Je traite avec Gravity et Mode en réglant mon tabLayout comme:
tabLayout.setTabGravity(TabLayout.GRAVITY_CENTER);
tabLayout.setTabMode(TabLayout.MODE_SCROLLABLE);
Donc, je suppose que s'il n'y a pas de place, l'onglet tabLayout est déroulable, mais s'il y a de la place, il est centré.
Des guides:
public static final int GRAVITY_CENTER Gravity avait l'habitude de disposer le onglets au centre de TabLayout.
public static final int GRAVITY_FILL Gravité utilisée pour remplir le fichier TabLayout autant que possible. Cette option ne prend effet que lorsqu'elle est utilisée avec MODE_FIXED.
public static final int MODE_FIXED Les onglets fixes affichent tous les onglets en même temps et sont mieux utilisés avec un contenu qui profite de quick pivote entre les onglets. Le nombre maximal d'onglets est limité par le la largeur de la vue. Les onglets fixes ont une largeur égale, basée sur l'onglet le plus large étiquette.
public static final int MODE_SCROLLABLE Les onglets déroulants affichent un sous-ensemble d'onglets à tout moment, et peut contenir des étiquettes d'onglets plus longues et un plus grand nombre d'onglets. Ils sont mieux utilisés pour les contextes de navigation interfaces tactiles lorsque les utilisateurs n'ont pas besoin de comparer directement l'onglet Étiquettes.
Donc, GRAVITY_FILL est compatible uniquement avec MODE_FIXED, mais, cela ne spécifie rien pour GRAVITY_CENTER, je l’attends pour être compatible avec MODE_SCROLLABLE, mais c’est ce que je reçois avec GRAVITY_CENTER et MODE_SCROLLABLE.
Donc, il utilise SCROLLABLE dans les deux orientations, mais pas GRAVITY_CENTER.
C'est ce que j'attendrais du paysage. mais pour avoir cela, je dois définir MODE_FIXED, donc ce que je reçois en portrait est:
Pourquoi GRAVITY_CENTER ne fonctionne-t-il pas avec SCROLLABLE si l'onglet tabLayout convient à l'écran? Existe-t-il un moyen de régler la gravité et le mode de manière dynamique (et de voir ce que j'attends)?
Merci beaucoup!
EDITED: Ceci est la mise en page de mon 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" />
Comme je n'ai pas trouvé pourquoi ce problème se produit, j'ai utilisé le code suivant:
float myTabLayoutSize = 360;
if (DeviceInfo.getWidthDP(this) >= myTabLayoutSize ){
tabLayout.setTabMode(TabLayout.MODE_FIXED);
} else {
tabLayout.setTabMode(TabLayout.MODE_SCROLLABLE);
}
Fondamentalement, je dois calculer manuellement la largeur de mon tabLayout, puis je règle le mode de tabulation en fonction de l'adéquation du tabLayout à l'appareil.
J'obtiens manuellement la taille de la présentation parce que tous les onglets n'ont pas la même largeur en mode Scrollable, ce qui peut provoquer que certains noms utilisent 2 lignes comme cela m'est arrivé dans l'exemple.
La gravité par tabulation n’affecte que MODE_FIXED
.
Une solution possible consiste à définir votre layout_width
sur wrap_content
et votre layout_gravity
sur 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 les onglets sont plus petits que la largeur de l'écran, la TabLayout
sera elle aussi plus petite et centrée à cause de la gravité. Si les onglets sont plus grands que la largeur de l'écran, TabLayout
correspond à la largeur de l'écran et le défilement est activé.
voici comment je l'ai fait
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);
}
}
};
J'ai légèrement modifié la solution de @Mario Velasco sur la partie exécutable
Regardez Android-tablayouthelper
Basculez automatiquement TabLayout.MODE_FIXED et TabLayout.MODE_SCROLLABLE dépend de la largeur totale de l'onglet.
garde les choses simples il suffit d'ajouter app: tabMode = "scrollable" et Android: layout_gravity = "bottom"
juste comme ça
<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" />
C’est la solution que j’ai utilisée pour changer automatiquement entre SCROLLABLE
et FIXED
+ FILL
. C'est le code complet de la solution @ Fighter42:
(Le code ci-dessous montre où placer la modification si vous avez utilisé le modèle d'activité à onglets 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);
}
}
});
}
Disposition:
<Android.support.design.widget.TabLayout
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:layout_gravity="center_horizontal" />
Si vous n'avez pas besoin de remplir la largeur, utilisez de préférence la solution @karaokyo.
J'ai créé une classe AdaptiveTabLayout pour y parvenir. C’est le seul moyen que j’ai trouvé de résoudre le problème, de répondre à la question et d’éviter/de résoudre les problèmes qui ne sont pas résolus.
Remarques:
MODE_SCROLLABLE
mais pas assez d'espace pour MODE_FIXED
. Si Vous ne gérez pas ce cas, cela se produira sur certains appareils. Vous verrez alors différentes tailles de texte ou ferez glisser deux lignes de texte dans certains onglets, ce qui paraît mauvais.wrap_content
sur le xml. Ne définissez aucun mode ou gravité sur le 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;
}
}
Et voici la classe 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;
}
}
Exemple d'utilisation:
<?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>
Problèmes/Demander de l'aide:
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
Je ne sais pas comment le résoudre. Aucune suggestion?
C'est le seul code qui a fonctionné pour moi:
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));
}
});
}
Les DisplayMetrics peuvent être récupérés en utilisant ceci:
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;
}
Et votre XML TabLayout devrait ressembler à ceci (n'oubliez pas de définir tabMaxWidth sur 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"/>
J'ai résolu ceci en utilisant ce qui suit
if(tabLayout_chemistCategory.getTabCount()<4)
{
tabLayout_chemistCategory.setTabGravity(TabLayout.GRAVITY_FILL);
}else
{
tabLayout_chemistCategory.setTabMode(TabLayout.MODE_SCROLLABLE);
}
Tout ce dont vous avez besoin est d’ajouter ce qui suit à votre TabLayout
custom:tabGravity="fill"
Alors vous aurez:
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"
/>
Exemple très simple et ça marche toujours.
/**
* 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);
});
}
<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"/>
Ma solution finale
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
}
}
}