package org.schabi.newpipe.views; import android.content.Context; import android.util.AttributeSet; import android.view.View; import androidx.annotation.NonNull; import com.google.android.material.tabs.TabLayout; /** * A TabLayout that is scrollable when tabs exceed its width. * Hides when there are less than 2 tabs. */ public class ScrollableTabLayout extends TabLayout { private static final String TAG = ScrollableTabLayout.class.getSimpleName(); private int layoutWidth = 0; private int prevVisibility = View.GONE; public ScrollableTabLayout(final Context context) { super(context); } public ScrollableTabLayout(final Context context, final AttributeSet attrs) { super(context, attrs); } public ScrollableTabLayout(final Context context, final AttributeSet attrs, final int defStyleAttr) { super(context, attrs, defStyleAttr); } @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); remeasureTabs(); } @Override protected void onSizeChanged(final int w, final int h, final int oldw, final int oldh) { super.onSizeChanged(w, h, oldw, oldh); layoutWidth = w; } @Override public void addTab(@NonNull final Tab tab, final int position, final boolean setSelected) { super.addTab(tab, position, setSelected); hasMultipleTabs(); // Adding a tab won't decrease total tabs' width so tabMode won't have to change to FIXED if (getTabMode() != MODE_SCROLLABLE) { remeasureTabs(); } } @Override public void removeTabAt(final int position) { super.removeTabAt(position); hasMultipleTabs(); // Removing a tab won't increase total tabs' width // so tabMode won't have to change to SCROLLABLE if (getTabMode() != MODE_FIXED) { remeasureTabs(); } } @Override protected void onVisibilityChanged(final View changedView, final int visibility) { super.onVisibilityChanged(changedView, visibility); // Check width if some tabs have been added/removed while ScrollableTabLayout was invisible // We don't have to check if it was GONE because then requestLayout() will be called if (changedView == this) { if (prevVisibility == View.INVISIBLE) { remeasureTabs(); } prevVisibility = visibility; } } private void setMode(final int mode) { if (mode == getTabMode()) { return; } setTabMode(mode); } /** * Make ScrollableTabLayout not visible if there are less than two tabs. */ private void hasMultipleTabs() { if (getTabCount() > 1) { setVisibility(View.VISIBLE); } else { setVisibility(View.GONE); } } /** * Calculate minimal width required by tabs and set tabMode accordingly. */ private void remeasureTabs() { if (prevVisibility != View.VISIBLE) { return; } if (layoutWidth == 0) { return; } final int count = getTabCount(); int contentWidth = 0; for (int i = 0; i < count; i++) { final View child = getTabAt(i).view; if (child.getVisibility() == View.VISIBLE) { // Use tab's minimum requested width should actual content be too small contentWidth += Math.max(child.getMinimumWidth(), child.getMeasuredWidth()); } } if (contentWidth > layoutWidth) { setMode(TabLayout.MODE_SCROLLABLE); } else { setMode(TabLayout.MODE_FIXED); } } }