Java tutorial
/******************************************************************************* * * Messenger Android Frontend * (C) 2013-2016 Nikolai Kudashov * (C) 2017 Bjrn Petersen * Contact: r10s@b44t.com, http://b44t.com * * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation, either version 3 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program. If not, see http://www.gnu.org/licenses/ . * ******************************************************************************/ package com.b44t.ui.Components; import android.content.Context; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Paint.Style; import android.os.Build; import android.support.v4.view.ViewPager; import android.support.v4.view.ViewPager.OnPageChangeListener; import android.view.View; import android.view.ViewTreeObserver.OnGlobalLayoutListener; import android.widget.FrameLayout; import android.widget.HorizontalScrollView; import android.widget.ImageView; import android.widget.LinearLayout; import com.b44t.messenger.AndroidUtilities; public class PagerSlidingTabStrip extends HorizontalScrollView { public interface IconTabProvider { int getPageIconResId(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 int lastScrollX = 0; public PagerSlidingTabStrip(Context context) { super(context); 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()).getPageIconResId(i)); } } updateTabStyles(); getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() { @Override public void onGlobalLayout() { if (Build.VERSION.SDK_INT < 16) { getViewTreeObserver().removeGlobalOnLayoutListener(this); } else { getViewTreeObserver().removeOnGlobalLayoutListener(this); } currentPosition = pager.getCurrentItem(); scrollToChild(currentPosition, 0); } }); } private void addIconTab(final int position, int resId) { ImageView tab = new ImageView(getContext()); tab.setFocusable(true); tab.setImageResource(resId); tab.setScaleType(ImageView.ScaleType.CENTER); tab.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { pager.setCurrentItem(position); } }); tabsContainer.addView(tab); tab.setSelected(position == currentPosition); } 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(-1, -1, 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; } int newScrollX = tabsContainer.getChildAt(position).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(); // draw underline rectPaint.setColor(underlineColor); canvas.drawRect(0, height - underlineHeight, tabsContainer.getWidth(), height, rectPaint); // default: line below current tab View currentTab = tabsContainer.getChildAt(currentPosition); float lineLeft = currentTab.getLeft(); float lineRight = currentTab.getRight(); // if there is an offset, start interpolating left and right coordinates between current and next tab 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); } // draw indicator line 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; 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); } } } public void onSizeChanged(int paramInt1, int paramInt2, int paramInt3, int paramInt4) { if (!shouldExpand) { post(new Runnable() { public void run() { 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; } }