NekoX/TMessagesProj/src/main/java/org/telegram/ui/Components/PagerSlidingTabStrip.java

378 lines
13 KiB
Java

/*
* This is the source code of Telegram for Android v. 5.x.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
*
* Copyright Nikolai Kudashov, 2013-2018.
*/
package org.telegram.ui.Components;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.RippleDrawable;
import android.os.Build;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.widget.FrameLayout;
import android.widget.HorizontalScrollView;
import android.widget.ImageView;
import android.widget.LinearLayout;
import androidx.viewpager.widget.ViewPager;
import androidx.viewpager.widget.ViewPager.OnPageChangeListener;
import org.telegram.messenger.AndroidUtilities;
import org.telegram.ui.ActionBar.Theme;
public class PagerSlidingTabStrip extends HorizontalScrollView {
public interface IconTabProvider {
Drawable getPageIconDrawable(int position);
void customOnDraw(Canvas canvas, int position);
boolean canScrollToTab(int position);
}
private LinearLayout.LayoutParams defaultTabLayoutParams;
private final PageListener pageListener = new PageListener();
public OnPageChangeListener delegatePageListener;
private LinearLayout tabsContainer;
private ViewPager pager;
private int tabCount;
private int currentPosition = 0;
private float currentPositionOffset = 0f;
private Paint rectPaint;
private int indicatorColor = 0xff666666;
private int underlineColor = 0x1a000000;
private boolean shouldExpand = false;
private int scrollOffset = AndroidUtilities.dp(52);
private int indicatorHeight = AndroidUtilities.dp(8);
private int underlineHeight = AndroidUtilities.dp(2);
private int dividerPadding = AndroidUtilities.dp(12);
private int tabPadding = AndroidUtilities.dp(24);
private Theme.ResourcesProvider resourcesProvider;
private int lastScrollX = 0;
public PagerSlidingTabStrip(Context context, Theme.ResourcesProvider resourcesProvider) {
super(context);
this.resourcesProvider = resourcesProvider;
setFillViewport(true);
setWillNotDraw(false);
tabsContainer = new LinearLayout(context);
tabsContainer.setOrientation(LinearLayout.HORIZONTAL);
tabsContainer.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutHelper.MATCH_PARENT));
addView(tabsContainer);
rectPaint = new Paint();
rectPaint.setAntiAlias(true);
rectPaint.setStyle(Style.FILL);
defaultTabLayoutParams = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutHelper.MATCH_PARENT);
}
public void setViewPager(ViewPager pager) {
this.pager = pager;
if (pager.getAdapter() == null) {
throw new IllegalStateException("ViewPager does not have adapter instance.");
}
pager.setOnPageChangeListener(pageListener);
notifyDataSetChanged();
}
public void setOnPageChangeListener(OnPageChangeListener listener) {
this.delegatePageListener = listener;
}
public void notifyDataSetChanged() {
tabsContainer.removeAllViews();
tabCount = pager.getAdapter().getCount();
for (int i = 0; i < tabCount; i++) {
if (pager.getAdapter() instanceof IconTabProvider) {
addIconTab(i, ((IconTabProvider) pager.getAdapter()).getPageIconDrawable(i), pager.getAdapter().getPageTitle(i));
}
}
updateTabStyles();
getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
getViewTreeObserver().removeOnGlobalLayoutListener(this);
currentPosition = pager.getCurrentItem();
scrollToChild(currentPosition, 0);
}
});
}
public View getTab(int position) {
if (position < 0 || position >= tabsContainer.getChildCount()) {
return null;
}
return tabsContainer.getChildAt(position);
}
private void addIconTab(final int position, Drawable drawable, CharSequence contentDescription) {
ImageView tab = new ImageView(getContext()) {
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (pager.getAdapter() instanceof IconTabProvider) {
((IconTabProvider) pager.getAdapter()).customOnDraw(canvas, position);
}
}
@Override
public void setSelected(boolean selected) {
super.setSelected(selected);
Drawable background = getBackground();
if (Build.VERSION.SDK_INT >= 21 && background != null) {
int color = getThemedColor(selected ? Theme.key_chat_emojiPanelIconSelected : Theme.key_chat_emojiBottomPanelIcon);
Theme.setSelectorDrawableColor(background, Color.argb(30, Color.red(color), Color.green(color), Color.blue(color)), true);
}
}
};
tab.setFocusable(true);
if (Build.VERSION.SDK_INT >= 21) {
RippleDrawable rippleDrawable = (RippleDrawable) Theme.createSelectorDrawable(getThemedColor(Theme.key_chat_emojiBottomPanelIcon), Theme.RIPPLE_MASK_CIRCLE_20DP, AndroidUtilities.dp(18));
Theme.setRippleDrawableForceSoftware(rippleDrawable);
tab.setBackground(rippleDrawable);
}
tab.setImageDrawable(drawable);
tab.setScaleType(ImageView.ScaleType.CENTER);
tab.setOnClickListener(v -> {
if (pager.getAdapter() instanceof IconTabProvider) {
if (!((IconTabProvider) pager.getAdapter()).canScrollToTab(position)) {
return;
}
}
pager.setCurrentItem(position, false);
});
tabsContainer.addView(tab);
tab.setSelected(position == currentPosition);
tab.setContentDescription(contentDescription);
}
private void updateTabStyles() {
for (int i = 0; i < tabCount; i++) {
View v = tabsContainer.getChildAt(i);
v.setLayoutParams(defaultTabLayoutParams);
if (shouldExpand) {
v.setPadding(0, 0, 0, 0);
v.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, 1.0F));
} else {
v.setPadding(tabPadding, 0, tabPadding, 0);
}
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (!shouldExpand || MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.UNSPECIFIED) {
return;
}
int myWidth = getMeasuredWidth();
tabsContainer.measure(MeasureSpec.EXACTLY | myWidth, heightMeasureSpec);
}
private void scrollToChild(int position, int offset) {
if (tabCount == 0) {
return;
}
View child = tabsContainer.getChildAt(position);
if (child == null) {
return;
}
int newScrollX = child.getLeft() + offset;
if (position > 0 || offset > 0) {
newScrollX -= scrollOffset;
}
if (newScrollX != lastScrollX) {
lastScrollX = newScrollX;
scrollTo(newScrollX, 0);
}
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (isInEditMode() || tabCount == 0) {
return;
}
final int height = getHeight();
if (underlineHeight != 0) {
rectPaint.setColor(underlineColor);
canvas.drawRect(0, height - underlineHeight, tabsContainer.getWidth(), height, rectPaint);
}
View currentTab = tabsContainer.getChildAt(currentPosition);
if (currentTab != null) {
float lineLeft = currentTab.getLeft();
float lineRight = currentTab.getRight();
if (currentPositionOffset > 0f && currentPosition < tabCount - 1) {
View nextTab = tabsContainer.getChildAt(currentPosition + 1);
final float nextTabLeft = nextTab.getLeft();
final float nextTabRight = nextTab.getRight();
lineLeft = (currentPositionOffset * nextTabLeft + (1f - currentPositionOffset) * lineLeft);
lineRight = (currentPositionOffset * nextTabRight + (1f - currentPositionOffset) * lineRight);
}
if (indicatorHeight != 0) {
rectPaint.setColor(indicatorColor);
canvas.drawRect(lineLeft, height - indicatorHeight, lineRight, height, rectPaint);
}
}
}
private class PageListener implements OnPageChangeListener {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
currentPosition = position;
currentPositionOffset = positionOffset;
View child = tabsContainer.getChildAt(position);
if (child != null) {
scrollToChild(position, (int) (positionOffset * tabsContainer.getChildAt(position).getWidth()));
invalidate();
if (delegatePageListener != null) {
delegatePageListener.onPageScrolled(position, positionOffset, positionOffsetPixels);
}
}
}
@Override
public void onPageScrollStateChanged(int state) {
if (state == ViewPager.SCROLL_STATE_IDLE) {
scrollToChild(pager.getCurrentItem(), 0);
}
if (delegatePageListener != null) {
delegatePageListener.onPageScrollStateChanged(state);
}
}
@Override
public void onPageSelected(int position) {
if (delegatePageListener != null) {
delegatePageListener.onPageSelected(position);
}
for (int a = 0; a < tabsContainer.getChildCount(); a++) {
tabsContainer.getChildAt(a).setSelected(a == position);
}
}
}
private int getThemedColor(String key) {
Integer color = resourcesProvider != null ? resourcesProvider.getColor(key) : null;
return color != null ? color : Theme.getColor(key);
}
public void onSizeChanged(int paramInt1, int paramInt2, int paramInt3, int paramInt4) {
if (!shouldExpand) {
post(PagerSlidingTabStrip.this::notifyDataSetChanged);
}
}
public void setIndicatorColor(int indicatorColor) {
this.indicatorColor = indicatorColor;
invalidate();
}
public void setIndicatorColorResource(int resId) {
this.indicatorColor = getResources().getColor(resId);
invalidate();
}
public int getIndicatorColor() {
return this.indicatorColor;
}
public void setIndicatorHeight(int indicatorLineHeightPx) {
this.indicatorHeight = indicatorLineHeightPx;
invalidate();
}
public int getIndicatorHeight() {
return indicatorHeight;
}
public void setUnderlineColor(int underlineColor) {
this.underlineColor = underlineColor;
invalidate();
}
public void setUnderlineColorResource(int resId) {
this.underlineColor = getResources().getColor(resId);
invalidate();
}
public int getUnderlineColor() {
return underlineColor;
}
public void setUnderlineHeight(int underlineHeightPx) {
this.underlineHeight = underlineHeightPx;
invalidate();
}
public int getUnderlineHeight() {
return underlineHeight;
}
public void setDividerPadding(int dividerPaddingPx) {
this.dividerPadding = dividerPaddingPx;
invalidate();
}
public int getDividerPadding() {
return dividerPadding;
}
public void setScrollOffset(int scrollOffsetPx) {
this.scrollOffset = scrollOffsetPx;
invalidate();
}
public int getScrollOffset() {
return scrollOffset;
}
public void setShouldExpand(boolean shouldExpand) {
this.shouldExpand = shouldExpand;
tabsContainer.setLayoutParams(new FrameLayout.LayoutParams(-1, -1));
updateTabStyles();
requestLayout();
}
public boolean getShouldExpand() {
return shouldExpand;
}
public void setTabPaddingLeftRight(int paddingPx) {
this.tabPadding = paddingPx;
updateTabStyles();
}
public int getTabPaddingLeftRight() {
return tabPadding;
}
}