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, es kann jedoch in einer Ausrichtung richtig angezeigt werden.
Ich beschäftige mich mit Schwerkraft und Modus und setze mein tabLayout wie folgt:
tabLayout.setTabGravity(TabLayout.GRAVITY_CENTER);
tabLayout.setTabMode(TabLayout.MODE_SCROLLABLE);
Ich gehe also davon aus, dass das tabLayout scrollbar ist, wenn kein Platz vorhanden ist. Wenn jedoch Platz vorhanden ist, wird es zentriert.
Von den Führern:
public static final int GRAVITY_CENTER Die Schwerkraft wird verwendet, um die Registerkarten in der Mitte des TabLayout.
public static final int GRAVITY_FILL Schwerkraft, mit der die .__ gefüllt wird. TabLayout so viel wie möglich. Diese Option wird nur wirksam, wenn sie verwendet wird mit MODE_FIXED.
public static final int MODE_FIXED Feste Registerkarten zeigen alle Registerkarten an gleichzeitig und werden am besten mit Inhalten verwendet, die von quick profitieren schwenkt zwischen den Laschen. Die maximale Anzahl der Registerkarten ist durch die .__ begrenzt. Breite der Ansicht. Feste Registerkarten haben dieselbe Breite, basierend auf der breitesten Registerkarte Etikette.
public static final int MODE_SCROLLABLE Rollbare Registerkarten zeigen eine .__ an. Untermenge von Registerkarten zu einem bestimmten Zeitpunkt und kann längere Registerkartenbezeichnungen enthalten und eine größere Anzahl von Registerkarten. Sie werden am besten zum Durchsuchen von Kontexten verwendet in Touch-Oberflächen, wenn Benutzer die Registerkarte nicht direkt vergleichen müssen Etiketten.
GRAVITY_FILL ist also nur mit MODE_FIXED kompatibel, aber bei ist nichts für GRAVITY_CENTER angegeben. Ich erwarte, dass es mit MODE_SCROLLABLE kompatibel ist. Dies ist jedoch, was ich mit GRAVITY_CENTER und MODE_SCROLLABLE bekomme
Es wird also SCROLLABLE in beiden Ausrichtungen verwendet, jedoch nicht GRAVITY_CENTER.
Das würde ich für Landschaft erwarten; aber um dies zu haben, muss ich MODE_FIXED setzen, also bekomme ich im Portrait:
Warum funktioniert GRAVITY_CENTER nicht für SCROLLABLE, wenn das tabLayout auf den Bildschirm passt? Gibt es eine Möglichkeit, die Schwerkraft und den Modus dynamisch einzustellen (und zu sehen, was ich erwarte)?
Vielen Dank!
BEARBEITET: Dies ist das Layout meines TabLayouts:
<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" />
Da ich nicht gefunden habe, warum dieses Verhalten auftritt, habe ich folgenden Code verwendet:
float myTabLayoutSize = 360;
if (DeviceInfo.getWidthDP(this) >= myTabLayoutSize ){
tabLayout.setTabMode(TabLayout.MODE_FIXED);
} else {
tabLayout.setTabMode(TabLayout.MODE_SCROLLABLE);
}
Grundsätzlich muss ich die Breite meines tabLayout manuell berechnen und dann den Tab-Modus einstellen, je nachdem, ob das tabLayout in das Gerät passt oder nicht.
Der Grund, warum ich die Größe des Layouts manuell erhalte, ist, dass nicht alle Registerkarten im scrollbaren Modus die gleiche Breite haben. Dies könnte dazu führen, dass einige Namen zwei Zeilen verwenden, wie es mir im Beispiel passiert ist.
Die Schwerkraft der Registerkarte wirkt sich nur auf MODE_FIXED
aus.
Eine mögliche Lösung besteht darin, Ihren layout_width
auf wrap_content
und layout_gravity
auf center_horizontal
zu setzen:
<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 Registerkarten kleiner als die Bildschirmbreite sind, ist auch die Variable TabLayout
kleiner und aufgrund der Schwerkraft zentriert. Wenn die Registerkarten größer als die Bildschirmbreite sind, stimmt die TabLayout
mit der Bildschirmbreite überein und der Bildlauf wird aktiviert.
so habe ich es gemacht
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 an der Lösung von @Mario Velasco im laufenden Bereich vorgenommen
Schau dir Android-Tablayouthelper an
Wechseln Sie automatisch zwischen TabLayout.MODE_FIXED und TabLayout.MODE_SCROLLABLE hängt von der Gesamtbreite der Registerkarten ab.
die Dinge bleiben einfach: Fügen Sie die App hinzu: tabMode = "scrollbar"
genau wie dieser
<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" />
Dies ist die Lösung, mit der ich automatisch zwischen SCROLLABLE
und FIXED
+ FILL
gewechselt habe. Es ist der vollständige Code für die @ Fighter42-Lösung:
(Der folgende Code zeigt, wo die Änderung eingefügt werden soll, wenn Sie die Aktivitätsvorlage mit Registern von Google 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 die Breite nicht ausfüllen müssen, sollten Sie die @karaokyo-Lösung verwenden.
Dafür habe ich eine AdaptiveTabLayout-Klasse erstellt. Dies war die einzige Möglichkeit, das Problem tatsächlich zu lösen, die Frage zu beantworten und Probleme zu vermeiden/zu umgehen, die andere Antworten hier nicht bieten.
Anmerkungen:
MODE_SCROLLABLE
, aber nicht genügend Platz für MODE_FIXED
. Wenn Sie mit diesem Fall nicht umgehen, wird dies auf einigen Geräten passieren. Sie werden unterschiedliche Textgrößen sehen oder zwei Textzeilen in einigen Registerkarten erstellen, die schlecht aussehen.wrap_content
in der XML-Datei sein. Stellen Sie keinen Modus oder die Schwerkraft in der XML ein.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;
}
}
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;
}
}
Beispiel verwenden:
<?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>
Probleme/Bitte um Hilfe:
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 ich es lösen kann. Irgendwelche Vorschläge?
Dies ist der einzige Code, der für mich funktioniert hat:
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 folgendermaßen abgerufen werden:
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;
}
Und Ihr TabLayout-XML sollte folgendermaßen aussehen (vergessen Sie nicht, tabMaxWidth auf 0 zu setzen):
<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"/>
Ich habe das mit folgendem gelöst
if(tabLayout_chemistCategory.getTabCount()<4)
{
tabLayout_chemistCategory.setTabGravity(TabLayout.GRAVITY_FILL);
}else
{
tabLayout_chemistCategory.setTabMode(TabLayout.MODE_SCROLLABLE);
}
Alles, was Sie brauchen, ist, Ihrem TabLayout folgendes hinzuzufügen
custom:tabGravity="fill"
So haben Sie dann:
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"
/>
Sehr einfaches Beispiel und es funktioniert immer.
/**
* 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"/>
Meine endgültige Lösung
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
}
}
}