Java tutorial
/* Copyright 2013 Andreas Stuetz Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package nit.contact.views; import android.annotation.SuppressLint; import android.content.Context; import android.content.res.ColorStateList; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Paint.Style; import android.graphics.Typeface; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; import android.support.v4.view.ViewPager; import android.support.v4.view.ViewPager.OnPageChangeListener; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.TypedValue; import android.view.Gravity; import android.view.View; import android.view.ViewGroup; import android.view.ViewTreeObserver.OnGlobalLayoutListener; import android.widget.HorizontalScrollView; import android.widget.LinearLayout; import android.widget.TextView; import java.util.Locale; /** * Custom ui sliding menu horizontal */ public class PagerSlidingTabStrip extends HorizontalScrollView { // @formatter:off private static final int[] ATTRS = new int[] { android.R.attr.textSize, android.R.attr.textColor }; private final PageListener pageListener = new PageListener(); // @formatter:on private final LinearLayout.LayoutParams defaultTabLayoutParams; private final LinearLayout.LayoutParams expandedTabLayoutParams; private final LinearLayout tabsContainer; private final Paint rectPaint; private final Paint dividerPaint; private final ColorStateList tabTextColorStateList = null; private final Typeface tabTypeface = null; private ViewPager mPager; private int tabCount; private int currentPosition = 0; private float currentPositionOffset = 0f; private int indicatorColor = 0xFF666666; private int underlineColor = 0x1A000000; private int dividerColor = 0x1A000000; private boolean shouldExpand = false; private boolean textAllCaps = true; private int scrollOffset = 52; private int indicatorHeight = 8; private int underlineHeight = 2; private int dividerPadding = 12; private int tabPadding = 24; private int tabTextSize = 12; private int tabTextColor = 0xFF666666; private int lastScrollX = 0; private Locale locale; public PagerSlidingTabStrip(Context context) { this(context, null); } public PagerSlidingTabStrip(Context context, AttributeSet attrs) { this(context, attrs, 0); } public PagerSlidingTabStrip(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); setFillViewport(true); setWillNotDraw(false); tabsContainer = new LinearLayout(context); tabsContainer.setOrientation(LinearLayout.HORIZONTAL); tabsContainer.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); addView(tabsContainer); DisplayMetrics dm = getResources().getDisplayMetrics(); scrollOffset = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, scrollOffset, dm); indicatorHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, indicatorHeight, dm); underlineHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, underlineHeight, dm); dividerPadding = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dividerPadding, dm); tabPadding = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, tabPadding, dm); int dividerWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1, dm); tabTextSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, tabTextSize, dm); // get system attrs (android:textSize and android:textColor) TypedArray a = context.obtainStyledAttributes(attrs, ATTRS); tabTextSize = a.getDimensionPixelSize(0, tabTextSize); tabTextColor = a.getColor(1, tabTextColor); a.recycle(); // get custom attrs a = context.obtainStyledAttributes(attrs, com.astuetz.pagerslidingtabstrip.R.styleable.PagerSlidingTabStrip); indicatorColor = a.getColor( com.astuetz.pagerslidingtabstrip.R.styleable.PagerSlidingTabStrip_pstsIndicatorColor, indicatorColor); underlineColor = a.getColor( com.astuetz.pagerslidingtabstrip.R.styleable.PagerSlidingTabStrip_pstsUnderlineColor, underlineColor); dividerColor = a.getColor( com.astuetz.pagerslidingtabstrip.R.styleable.PagerSlidingTabStrip_pstsDividerColor, dividerColor); indicatorHeight = a.getDimensionPixelSize( com.astuetz.pagerslidingtabstrip.R.styleable.PagerSlidingTabStrip_pstsIndicatorHeight, indicatorHeight); underlineHeight = a.getDimensionPixelSize( com.astuetz.pagerslidingtabstrip.R.styleable.PagerSlidingTabStrip_pstsUnderlineHeight, underlineHeight); dividerPadding = a.getDimensionPixelSize( com.astuetz.pagerslidingtabstrip.R.styleable.PagerSlidingTabStrip_pstsDividerPadding, dividerPadding); tabPadding = a.getDimensionPixelSize( com.astuetz.pagerslidingtabstrip.R.styleable.PagerSlidingTabStrip_pstsTabPaddingLeftRight, tabPadding); shouldExpand = a.getBoolean( com.astuetz.pagerslidingtabstrip.R.styleable.PagerSlidingTabStrip_pstsShouldExpand, shouldExpand); scrollOffset = a.getDimensionPixelSize( com.astuetz.pagerslidingtabstrip.R.styleable.PagerSlidingTabStrip_pstsScrollOffset, scrollOffset); textAllCaps = a.getBoolean( com.astuetz.pagerslidingtabstrip.R.styleable.PagerSlidingTabStrip_pstsTextAllCaps, textAllCaps); a.recycle(); rectPaint = new Paint(); rectPaint.setAntiAlias(true); rectPaint.setStyle(Style.FILL); dividerPaint = new Paint(); dividerPaint.setAntiAlias(true); dividerPaint.setStrokeWidth(dividerWidth); defaultTabLayoutParams = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT); expandedTabLayoutParams = new LinearLayout.LayoutParams(0, LayoutParams.MATCH_PARENT, 1.0f); if (locale == null) { locale = getResources().getConfiguration().locale; } } public void setViewPager(ViewPager pager) { this.mPager = pager; if (pager.getAdapter() == null) { throw new IllegalStateException("ViewPager does not have adapter instance."); } pager.setOnPageChangeListener(pageListener); notifyDataSetChanged(); } private void notifyDataSetChanged() { tabsContainer.removeAllViews(); tabCount = mPager.getAdapter().getCount(); for (int i = 0; i < tabCount; i++) { if (mPager.getAdapter() instanceof IconTabProvider) { // addIconTab(i, ((IconTabProvider) pager.getAdapter()).getPageIconResId(i)); // addCustomTab(i, pager.getAdapter().getPageTitle(i).toString(), // ((IconTabProvider) pager.getAdapter()).getPageIconResId(i)); addTabView(i); } else { addTextTab(i, mPager.getAdapter().getPageTitle(i).toString()); } } updateTabStyles(); getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() { @SuppressWarnings("deprecation") @SuppressLint("NewApi") @Override public void onGlobalLayout() { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { getViewTreeObserver().removeGlobalOnLayoutListener(this); } else { getViewTreeObserver().removeOnGlobalLayoutListener(this); } currentPosition = mPager.getCurrentItem(); tabsContainer.getChildAt(currentPosition).setSelected(true); scrollToChild(currentPosition, 0); } }); } private void addTextTab(final int position, String title) { TextView tab = new TextView(getContext()); tab.setText(title); tab.setGravity(Gravity.CENTER); tab.setSingleLine(); addTab(position, tab); } private void addTabView(int position) { LinearLayout view = new LinearLayout(getContext()); view.setOrientation(LinearLayout.VERTICAL); view.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); view.setGravity(Gravity.CENTER); view.setPadding(tabPadding, indicatorHeight, tabPadding, indicatorHeight); View tab = ((IconTabProvider) mPager.getAdapter()).getView(position); view.addView(tab); addTab(position, view); } private void addTab(final int position, View tab) { tab.setFocusable(true); tab.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if (mPager.getAdapter() instanceof IconTabProvider) { ((IconTabProvider) mPager.getAdapter()).onTabClick(position, mPager.getCurrentItem() == position); } mPager.setCurrentItem(position); } }); tabsContainer.addView(tab, position, shouldExpand ? expandedTabLayoutParams : defaultTabLayoutParams); } private void updateTabStyles() { for (int i = 0; i < tabCount; i++) { View v = tabsContainer.getChildAt(i); if (v instanceof TextView) { TextView tab = (TextView) v; tab.setTextSize(TypedValue.COMPLEX_UNIT_PX, tabTextSize); tab.setTypeface(tabTypeface, Typeface.BOLD); if (tabTextColorStateList != null) { tab.setTextColor(tabTextColorStateList); } else { tab.setTextColor(tabTextColor); } if (textAllCaps) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { tab.setAllCaps(true); } else { tab.setText(tab.getText().toString().toUpperCase(locale)); } } } else if (v instanceof ViewGroup) { int numChildView = ((ViewGroup) v).getChildCount(); View childView; for (int j = 0; j < numChildView; j++) { childView = ((ViewGroup) v).getChildAt(j); if (childView instanceof TextView) { TextView tab = (TextView) childView; tab.setTypeface(tabTypeface, Typeface.BOLD); if (tabTextColorStateList != null) { tab.setTextColor(tabTextColorStateList); } else { tab.setTextColor(tabTextColor); } // setAllCaps() is only available from API 14, so the upper case is made manually if we are on a // pre-ICS-build if (textAllCaps) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { tab.setAllCaps(true); } else { tab.setText(tab.getText().toString().toUpperCase(locale)); } } } } } } } 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 indicator line rectPaint.setColor(indicatorColor); // 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); } canvas.drawRect(lineLeft, height - indicatorHeight, lineRight, height, rectPaint); // draw underline rectPaint.setColor(underlineColor); canvas.drawRect(0, height - underlineHeight, tabsContainer.getWidth(), height, rectPaint); // draw divider dividerPaint.setColor(dividerColor); for (int i = 0; i < tabCount - 1; i++) { View tab = tabsContainer.getChildAt(i); canvas.drawLine(tab.getRight(), dividerPadding, tab.getRight(), height - dividerPadding, dividerPaint); } } @Override public void onRestoreInstanceState(Parcelable state) { SavedState savedState = (SavedState) state; super.onRestoreInstanceState(savedState.getSuperState()); currentPosition = savedState.currentPosition; requestLayout(); } @Override public Parcelable onSaveInstanceState() { Parcelable superState = super.onSaveInstanceState(); SavedState savedState = new SavedState(superState); savedState.currentPosition = currentPosition; return savedState; } /** * handle view item menu */ public interface IconTabProvider { View getView(int position); void onPageScrollState(int position); void onTabClick(int position, boolean isSameTab); } /** * save status pager and item menu */ static class SavedState extends BaseSavedState { public static final Creator<SavedState> CREATOR = new Creator<SavedState>() { @Override public SavedState createFromParcel(Parcel in) { return new SavedState(in); } @Override public SavedState[] newArray(int size) { return new SavedState[size]; } }; int currentPosition; public SavedState(Parcelable superState) { super(superState); } private SavedState(Parcel in) { super(in); currentPosition = in.readInt(); } @Override public void writeToParcel(Parcel dest, int flags) { super.writeToParcel(dest, flags); dest.writeInt(currentPosition); } } /** * handle viewPager listenr from tabStrip */ 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(); } @Override public void onPageScrollStateChanged(int state) { if (state == ViewPager.SCROLL_STATE_IDLE) { scrollToChild(mPager.getCurrentItem(), 0); } } @Override public void onPageSelected(int position) { if (mPager.getAdapter() instanceof IconTabProvider) { ((IconTabProvider) mPager.getAdapter()).onPageScrollState(position); } View layoutTab; for (int i = 0; i < tabsContainer.getChildCount(); i++) { layoutTab = tabsContainer.getChildAt(i); if (layoutTab instanceof ViewGroup) { for (int j = 0; j < ((ViewGroup) layoutTab).getChildCount(); j++) { ((ViewGroup) layoutTab).getChildAt(j).setSelected(i == position); } } } } } }