Próbuję użyć nowego projektu TabLayout w moim projekcie. Chcę, aby układ dostosowywał się do każdego rozmiaru i orientacji ekranu, ale można go poprawnie zobaczyć w jednej orientacji.
Mam do czynienia z Gravity and Mode ustawiając mój tabLayout jako:
tabLayout.setTabGravity(TabLayout.GRAVITY_CENTER);
tabLayout.setTabMode(TabLayout.MODE_SCROLLABLE);
Więc spodziewam się, że jeśli nie ma miejsca, tabLayout jest przewijalne, ale jeśli jest miejsce, jest wyśrodkowane.
Z przewodników:
public static final int GRAVITY_CENTER Grawitacja używana do układania zakładek w środku TabLayout.
public static final int GRAVITY_FILL Grawitacja używana do wypełnienia TabLayout tak bardzo, jak to możliwe. Ta opcja działa tylko wtedy, gdy jest używana z MODE_FIXED.
public static final int MODE_FIXED Stałe karty wyświetlają wszystkie karty jednocześnie i najlepiej ich używać z zawartością korzystającą z szybkiego przełączania między kartami. Maksymalna liczba zakładek jest ograniczona przez szerokość widoku. Stałe zakładki mają równą szerokość w oparciu o najszerszą etykietę.
public static final int MODE_SCROLLABLE Przewijalne karty wyświetlają podzbiór zakładek w dowolnym momencie i mogą zawierać dłuższe etykiety i większą liczbę zakładek. Najlepiej nadają się do przeglądania kontekstów w interfejsach dotykowych, gdy użytkownicy nie muszą bezpośrednio porównywać etykiet kart.
Więc GRAVITY_FILL jest kompatybilny tylko z MODE_FIXED, ale co nie określa niczego dla GRAVITY_CENTER, spodziewam się, że będzie kompatybilny z MODE_SCROLLABLE, ale to właśnie otrzymuję, używając GRAVITY_CENTER i MODE_SCROLLABLE
Tak więc używa SCROLLABLE w obu orientacjach, ale nie używa GRAVITY_CENTER.
Tego właśnie oczekiwałbym od krajobrazu; ale żeby to mieć, muszę ustawić MODE_FIXED, więc w portrecie otrzymuję:
Dlaczego GRAVITY_CENTER nie działa dla SCROLLABLE, jeśli tabLayout pasuje do ekranu? Czy istnieje sposób, aby dynamicznie ustawić grawitację i tryb (i zobaczyć, czego się spodziewam)?
Dziękuję Ci bardzo!
EDITED: To jest układ mojego 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" />
źródło
Odpowiedzi:
Efekty tylko grawitacji tabulatorów
MODE_FIXED
.Możliwym rozwiązaniem jest ustawienie
layout_width
sięwrap_content
ilayout_gravity
docenter_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" />
Jeśli zakładki są mniejsze niż szerokość ekranu, to
TabLayout
samo będzie mniejsze i będzie wyśrodkowane z powodu grawitacji. Jeśli zakładki są większe niż szerokość ekranu,TabLayout
dopasują się do szerokości ekranu i aktywuje się przewijanie.źródło
app:tabMaxWidth="0dp"
iandroid:layout_centerHorizontal="true"
praca w celu wyśrodkowania zakładek.tak to zrobiłem
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); } } };
Dokonałem niewielkich zmian w rozwiązaniu @Mario Velasco na części uruchamialnej
źródło
tabLayout.getWidth()
zawsze zwraca dla mnie zeroPonieważ nie znalazłem przyczyny takiego zachowania, użyłem następującego kodu:
float myTabLayoutSize = 360; if (DeviceInfo.getWidthDP(this) >= myTabLayoutSize ){ tabLayout.setTabMode(TabLayout.MODE_FIXED); } else { tabLayout.setTabMode(TabLayout.MODE_SCROLLABLE); }
Zasadniczo muszę ręcznie obliczyć szerokość mojego tabLayout, a następnie ustawiam tryb Tab w zależności od tego, czy tabLayout pasuje do urządzenia, czy nie.
Powodem, dla którego ręcznie otrzymuję rozmiar układu, jest to, że nie wszystkie karty mają tę samą szerokość w trybie przewijania, co może sprowokować, że niektóre nazwy używają 2 wierszy, jak mi się to zdarzyło w przykładzie.
źródło
sprawia, że wszystko jest proste, wystarczy dodać aplikację: tabMode = "scrollable" i android: layout_gravity = "bottom"
takie jak to
<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" />
źródło
Spójrz na android-tablayouthelper
źródło
To jest rozwiązanie, którego użyłem do automatycznej zmiany między
SCROLLABLE
iFIXED
+FILL
. To jest pełny kod rozwiązania @ Fighter42:(Poniższy kod pokazuje, gdzie umieścić modyfikację, jeśli użyłeś szablonu działań Google z kartami)
@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); } } }); }
Układ:
<android.support.design.widget.TabLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" />
Jeśli nie musisz wypełniać szerokości, lepiej użyj rozwiązania @karaokyo.
źródło
Aby to osiągnąć, stworzyłem klasę AdaptiveTabLayout. To był jedyny sposób, w jaki udało mi się rozwiązać problem, odpowiedzieć na pytanie i uniknąć / obejść problemy, których nie mają inne odpowiedzi.
Uwagi:
MODE_SCROLLABLE
ale za mało miejscaMODE_FIXED
. Jeśli nie poradzisz sobie z tym przypadkiem, stanie się to na niektórych urządzeniach, zobaczysz różne rozmiary tekstu lub wypalisz dwie linie tekstu w niektórych zakładkach, co wygląda źle.wrap_content
się w pliku xml. Nie ustawiaj żadnego trybu ani grawitacji w pliku 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; } }
A to jest klasa 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; } }
Użyj przykładu:
<?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>
Sens
Problemy / Poproś o pomoc:
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
Nie jestem pewien, jak to rozwiązać. Jakieś sugestie?
źródło
<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"/>
źródło
Bardzo prosty przykład i zawsze działa.
/** * 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); }); }
źródło
To jedyny kod, który działał dla mnie:
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 można pobrać za pomocą tego:
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; }
Twój XML TabLayout powinien wyglądać tak (nie zapomnij ustawić tabMaxWidth na 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"/>
źródło
Wszystko, czego potrzebujesz, to dodać następujące elementy do swojego TabLayout
custom:tabGravity="fill"
Więc będziesz miał:
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" />
źródło
Rozwiązałem to za pomocą następujących
if(tabLayout_chemistCategory.getTabCount()<4) { tabLayout_chemistCategory.setTabGravity(TabLayout.GRAVITY_FILL); }else { tabLayout_chemistCategory.setTabMode(TabLayout.MODE_SCROLLABLE); }
źródło
Moje ostateczne rozwiązanie
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 } } }
źródło