NewPipe/app/src/main/java/org/schabi/newpipe/views/ScrollableTabLayout.java

135 lines
3.8 KiB
Java

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