2015-06-03 19 views
73

Ich versuche, das neue Design TabLayout in meinem Projekt zu verwenden. Ich möchte, dass sich das Layout an jede Bildschirmgröße und -ausrichtung anpasst, aber in einer Ausrichtung richtig angezeigt wird.Android Support Design TabLayout: Gravity Center und Modus scrollbar

ich mit Gravity zu tun habe und Moduseinstellung meine tabLayout als:

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

Damit ich erwarten, wenn kein Raum ist, der tabLayout scrollbaren ist, aber wenn es Raum ist, wird es zentriert.

Von den Führungen:

public static final int GRAVITY_CENTER Gravity verwendet, um die Registerkarten in der Mitte des TabLayout zu legen.

public static final int GRAVITY_FILL Schwerkraft verwendet, um die TabLayout so viel wie möglich zu füllen. Diese Option wird nur wirksam, wenn mit MODE_FIXED verwendet wird.

public static final int MODE_FIXED Feste Tabs angezeigt werden alle Registerkarten gleichzeitig und mit Inhalt am besten verwendet, die von schnellen schwenkt zwischen den Tabs zu Gute kommt. Die maximale Anzahl von Tabs ist durch die Breite der Ansicht begrenzt. Feste Tabs haben die gleiche Breite, basierend auf dem breitesten Tab Label.

public static final int MODE_SCROLLABLE Scrollbare Registerkarten zeigen zu jedem Zeitpunkt eine Untergruppe von Registerkarten an und können längere Registerkartenbeschriftungen und eine größere Anzahl von Registerkarten enthalten. Sie werden am besten für das Durchsuchen von Kontexten verwendet, die in In-Touch-Schnittstellen enthalten sind, wenn Benutzer die Registerkarte Etiketten nicht direkt vergleichen müssen.

So GRAVITY_FILL ist nur mit MODE_FIXED aber zumin gibt nichts spezifiziert für GRAVITY_CENTER erwarte ich, dass es mit MODE_SCROLLABLE kompatibel sein, aber das ist, was ich GRAVITY_CENTER und MODE_SCROLLABLE erhalten mit

enter image description here

So verwendet SCROLLABLE in beiden Ausrichtungen, aber es verwendet nicht GRAVITY_CENTER.

Dies ist, was ich für Landschaft erwarten würde; aber diese zu haben, ich brauche MODE_FIXED zu setzen, so, was ich im Portrait bekommen ist:

enter image description here

Warum ist GRAVITY_CENTER nicht funktioniert für SCROLLABLE, wenn der tabLayout den Bildschirm passt? Gibt es eine Möglichkeit, Schwerkraft und Modus dynamisch einzustellen (und zu sehen, was ich erwarte)?

Vielen Dank!

EDITED: Dies ist das Layout meiner 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" /> 
+0

@ Fighter42 folgende Verwendung haben Sie eine Lösung für diese gefunden? Ich stehe vor dem gleichen Problem. – Spynet

+0

Der einzige Weg, den ich gefunden habe, war, die Größe Ihrer Tabs (manuell) zu erhalten und dann die Layout-Parameter dynamisch zu konfigurieren, je nachdem, ob es passt oder nicht. –

+0

@ Fighter42, können Sie einen Beispielcode für die von Ihnen verwendete Lösung posten? – Sammys

Antwort

3

Da ich nicht das finden warum dieses Verhalten happen Ich habe den folgenden Code verwendet:

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

Grundsätzlich habe ich um die Breite meiner TabLayout manuell zu berechnen und dann setze ich den Tab Mode abhängig davon, ob TabLayout in das Gerät passt oder nicht.

Der Grund, warum ich die Größe des Layouts manuell erhalten, ist, weil nicht alle Registerkarten im Scrollable-Modus die gleiche Breite haben, was dazu führen könnte, dass einige Namen 2 Zeilen verwenden, wie es mir im Beispiel passiert ist.

+0

Mit dieser Lösung könnte der Text potentiell geschrumpft werden und auch 2 Zeilen verwenden. Siehe andere Antworten und Lösungen in diesem Thread dazu. Sie verringern das Risiko dieses Erscheinens, erscheinen aber oft, wenn das TabLayout ein wenig kleiner als die screenWidth ist. – Sotti

87

Tab Schwerkraft nur Effekte MODE_FIXED.

Eine mögliche Lösung ist Ihr layout_width-wrap_content zu setzen und 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" /> 

Wenn die Laschen kleiner sind als die Bildschirmbreite, die TabLayout selbst wird auch kleiner sein, und es wird wegen zentriert die Schwerkraft. Wenn die Tabs größer als die Bildschirmbreite sind, passt TabLayout der Bildschirmbreite und Scrollen wird aktiviert.

+1

Ich verwende Material Design für meine App. Ich folgte der Probe von http://www.androidhive.info/2015/09/android-material-design-working-with-tabs/ Tab scrollbar funktioniert nicht in Kitkat und Jelly Bean-Geräten. In Lollipop kann ich Tab scrollen, aber in anderen als Lollipop-Geräten funktioniert die scrollbare Registerkarte nicht, aber Swipe funktioniert gut. Darf ich wissen, was das Problem sein würde. – user2681579

+0

Dies funktionierte nicht für mich auf API 15/support.design:25.1.0. Tabs wurden linksbündig ausgerichtet, wenn sie schmaler als die Fensterbreite sind. Das Setzen von 'app: tabMaxWidth =" 0dp "' und 'android: layout_centerHorizontal =" true "' hat zum Zentrieren der Tabs funktioniert. – Baker

+0

Es hat für mich funktioniert. Tabs sind immer zentriert, aber wenn sie nicht scrollbar sind, füllen sie nicht die ganze Breite. –

7

Blick auf android-tablayouthelper

Automatisches Umschalten TabLayout.MODE_FIXED und TabLayout.MODE_SCROLLABLE hängt von insgesamt Tabulatorbreite.

+0

Aber wenn Registerkarte Titel dynamisch sind. Der Text geht in die nächste Zeile. Und wenn benutzerdefinierte Layout für Registerkarte verwenden. Text Ellipsize am Ende wie – Nepster

4

Dies ist die Lösung, die ich automatisch zwischen SCROLLABLE und FIXED + FILL ändern verwendet. Es ist der vollständige Code für die @ Fighter42 Lösung:

(Der folgende Code zeigt, wo die Änderung setzen, wenn Sie die Google-Vorlage Tabbed-Aktivität verwendet haben)

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

Layout:

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

Wenn Sie nicht Breite füllen müssen, besser zu verwenden @ karaokyo Lösung.

+0

das funktioniert gut; Der Wechsel zwischen Querformat und Hochformat macht genau das, was Sie erwarten. Google sollte dies in der Standardvorlage für Aktivitäten mit Registerkarten implementieren. –

+0

Diese Antwort hat die gleichen Probleme, die ich in der Tiago-Lösung erwähnt habe. – Sotti

10

das ist, wie ich es tat

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

Ich habe kleine Änderungen von @Mario Velascos Lösung auf dem runnable Teil

+0

Diese Lösung hat dieselben Probleme, die ich bei der Lösung von Tiago erwähnt habe. – Sotti

+0

Diese Lösung funktioniert auf Registerkarte ohne Symbol, was ist, wenn ich Symbol mit Text habe? :/ –

+0

@EmreTekin ja es funktioniert mit einem Symbol, meine Tabs hatten Icons mit Text – Flux

1

Dies ist der einzige Code, der für mich gearbeitet:

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

Die DisplayMetrics kann mit diesem abgerufen werden:

Und Ihre TabLayout XML sollte wie folgt aussehen (vergessen Sie nicht tabMaxWidth auf 0 eingestellt):

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

Dies ist fast da, aber es gibt einige Probleme.Das offensichtlichste Problem ist, dass auf einigen Geräten (und den meisten langsamen) tatsächlich gesehen wird, wie das Layout geändert und geändert wird. – Sotti

+1

Es gibt ein anderes Problem. Dieser Ansatz misst die Gesamtbreite des TabLayouts, um zu entscheiden, ob es scrollbar sein soll oder nicht. Das ist nicht sehr genau. Es gibt Situationen, in denen das TabLayout im scrollbaren Modus nicht beide Kanten erreicht, aber es gibt keinen Platz für den festen Modus, ohne den Text zu verkleinern, der die Anzahl der Zeilen auf der Registerkarte missbraucht (normalerweise 2). Dies ist eine direkte Konsequenz davon, dass die Registerkarten im festen Modus eine feste Breite haben (screenWidth/numberOfTabs), während sie im scrollbaren Modus den Text + Paddings umhüllen. – Sotti

4

hält die Dinge einfach app nur hinzufügen: tabmode = "scrollable" und android: layout_gravity = "bottom"

wie diese

<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

+3

Das ist nicht das, wonach der Schöpfer fragt. Das Problem bei diesem Ansatz besteht darin, dass Sie in Szenarien mit zwei Tabs oder drei Tabs auf Handys mit kleinem Text ein Layout wie den Google Play Store haben, in dem sich die Tabs auf der linken Seite befinden. Der Ersteller möchte, dass die Registerkarten von Kante zu Kante reichen, wenn dies möglich ist, und andernfalls blättern. – Sotti

2

Alles, was Sie brauchen, ist Folgendes zu Ihrer TabLayout

custom:tabGravity="fill" 

So hinzuzufügen dann musst du:

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

Das ist nicht das, wonach der Schöpfer fragt. Die Probleme hier sind die Tabs werden nie scrollbar sein, und Sie werden Platz auf dem Bildschirm loswerden. Die Tabs fangen an, den Text zu verkleinern und schließlich werden zwei ausgekleidet. – Sotti

1

ich eine AdaptiveTabLayout Klasse erstellt, dies zu erreichen. Dies war die einzige Möglichkeit, das Problem zu lösen, die Frage zu beantworten und Probleme zu vermeiden, die andere Antworten hier nicht haben.

Hinweise:

  • Griffe Telefon/Tablet-Layouts.
  • Griffe Fälle, wo es genug Raum für MODE_SCROLLABLE gibt, aber nicht genug Platz für MODE_FIXED. Wenn Sie nicht diesen Fall behandeln, wird es auf einigen Geräten passieren, die Sie sehen verschiedene Textgrößen oder Ofen zwei Zeilen Text in einigen Tabs, die sieht schlecht aus.
  • Es bekommt echte Maßnahmen und macht keine Annahmen (wie Bildschirm ist 360dp breit oder was auch immer ...). Dies funktioniert mit realen Bildschirmgrößen und echten Tabgrößen. Dies bedeutet, dass die Übersetzung gut funktioniert, da keine Tabulatorgröße angenommen wird.
  • Angebote mit den verschiedenen Übergängen auf der onLayout-Phase, um vermeiden zusätzliche Arbeit.
  • Die Layoutbreite muss wrap_content auf dem XML sein. Setzen Sie keinen Modus oder Schwerkraft auf das XML.

AdaptivesTabLayout.

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

} 

Und das ist die DeviceUtils Klasse:

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

} 

Anwendungsbeispiel:

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

Probleme/um Hilfe bitten:

  • Sie werden sehen:

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 

Ich bin nicht sicher, wie es zu lösen. Irgendwelche Vorschläge?

  • Um die TabLayout Kind Maßnahmen zu machen, ich habe einige Abgüsse und Annahmen (wie das Kind ist ein Linearlayout andere Ansichten enthält ....) Dies könnte Probleme mit in weiterem Design Support-Bibliothek Updates verursachen. Ein besserer Ansatz/Vorschläge?
0

Ich löste dieses

if(tabLayout_chemistCategory.getTabCount()<4) 
    { 
     tabLayout_chemistCategory.setTabGravity(TabLayout.GRAVITY_FILL); 
    }else 
    { 
     tabLayout_chemistCategory.setTabMode(TabLayout.MODE_SCROLLABLE); 

    }