Java tutorial
/* * Copyright (C) 2011 The Android Open Source Project * Copyright (C) 2011 Jake Wharton * * 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 com.resonos.apps.library.tabviewpager; import android.content.Context; import android.graphics.drawable.Drawable; import android.support.v4.view.PagerAdapter; import android.support.v4.view.ViewPager; import android.support.v4.view.ViewPager.OnPageChangeListener; import android.text.Layout.Alignment; import android.text.StaticLayout; import android.text.TextPaint; import android.util.AttributeSet; import android.util.FloatMath; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.HorizontalScrollView; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; import com.resonos.app.library.R; /** * This is a modified version of a class from Jake Wharton's ViewPagerIndicator. * * This widget implements the dynamic action bar tab behavior that can change * across different configurations or circumstances. */ public class TabPageIndicator extends HorizontalScrollView implements PageIndicator, OnClickListener { // constants private static final int MAX_TAB_WIDTH = 800; // objects private LinearLayout mTabLayout; private ViewPager mViewPager; protected ViewPager.OnPageChangeListener mListener, mListener2 = null; private LayoutInflater mInflater; private Runnable mTabSelector; private TextPaint mTextPaint; // vars private int mTextPadding = 0, mTotalMinWidth = 0, mTargetWidth = 0; private int[] mAllMinWidths; private boolean mRescaleTabs = false; private int mMaxTabWidth; private int mSelectedTabIndex; public TabPageIndicator(Context context) { this(context, null); } public TabPageIndicator(Context context, AttributeSet attrs) { super(context, attrs); setHorizontalScrollBarEnabled(false); mInflater = LayoutInflater.from(context); mTabLayout = new LinearLayout(getContext()); addView(mTabLayout, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.MATCH_PARENT)); } @Override public void onClick(View view) { if (view instanceof TabView) { TabView tabView = (TabView) view; setCurrentView(tabView.getIndex()); } } @Override public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { if (mViewPager == null) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); return; } final int widthMode = MeasureSpec.getMode(widthMeasureSpec); final boolean lockedExpanded = widthMode == MeasureSpec.EXACTLY; mTargetWidth = MeasureSpec.getSize(widthMeasureSpec); mRescaleTabs = mTotalMinWidth < mTargetWidth; final int childCount = mTabLayout.getChildCount(); if (childCount > 1 && (widthMode == MeasureSpec.EXACTLY || widthMode == MeasureSpec.AT_MOST)) { if (childCount > 2) { mMaxTabWidth = (int) (MeasureSpec.getSize(widthMeasureSpec) * 0.4f); } else { mMaxTabWidth = (int) (MeasureSpec.getSize(widthMeasureSpec) * 0.55f); } } else { mMaxTabWidth = -1; } final int oldWidth = getMeasuredWidth(); super.onMeasure(widthMeasureSpec, heightMeasureSpec); final int newWidth = getMeasuredWidth(); if (lockedExpanded && oldWidth != newWidth) { // Recenter the tab display if we're at a new (scrollable) size. setCurrentItemImpl(mSelectedTabIndex); // bypass any override } } /** * Return the tab at a given position * @param position : the tab index * @return a {@link TabView} object, or null if not found */ public TabView getTabAt(int position) { return (TabView) mTabLayout.getChildAt(position); } /** * Animate to a given tab position and select it * @param position : the tab index */ private void animateToTab(final int position) { final View tabView = mTabLayout.getChildAt(position); if (mTabSelector != null) { removeCallbacks(mTabSelector); } mTabSelector = new Runnable() { public void run() { final int scrollPos = tabView.getLeft() - (getWidth() - tabView.getWidth()) / 2; smoothScrollTo(scrollPos, 0); mTabSelector = null; } }; post(mTabSelector); } @Override public void onAttachedToWindow() { super.onAttachedToWindow(); if (mTabSelector != null) { // Re-post the selector we saved post(mTabSelector); } } @Override public void onDetachedFromWindow() { super.onDetachedFromWindow(); if (mTabSelector != null) { removeCallbacks(mTabSelector); } } /** * Add a tab to the indicator */ private void addTab(String text, Drawable drawable, int index, boolean visible) { //Workaround for not being able to pass a defStyle on pre-3.0 final TabView tabView = (TabView) mInflater.inflate(R.layout.vpi__tab, null); tabView.init(this, text, index); tabView.setFocusable(true); tabView.setOnClickListener(this); if (drawable != null) tabView.setIcon(drawable); tabView.setVisibility(visible ? View.VISIBLE : View.GONE); mTabLayout.addView(tabView, new LinearLayout.LayoutParams(0, LayoutParams.MATCH_PARENT, 1)); } @Override public void onPageScrollStateChanged(int arg0) { if (mListener != null) mListener.onPageScrollStateChanged(arg0); if (mListener2 != null) mListener2.onPageScrollStateChanged(arg0); } @Override public void onPageScrolled(int arg0, float arg1, int arg2) { if (mListener != null) mListener.onPageScrolled(arg0, arg1, arg2); if (mListener2 != null) mListener2.onPageScrolled(arg0, arg1, arg2); } @Override public void onPageSelected(int view) { setCurrentItem(view); if (mListener != null) mListener.onPageSelected(view); if (mListener2 != null) mListener2.onPageSelected(view); } @Override public void setViewPager(ViewPager view) { final PagerAdapter adapter = view.getAdapter(); if (adapter == null) { throw new IllegalStateException("ViewPager does not have adapter instance."); } if (!(adapter instanceof TitleProvider)) { throw new IllegalStateException( "ViewPager adapter must implement TitleProvider to be used with TitlePageIndicator."); } mViewPager = view; view.setOnPageChangeListener(this); notifyDataSetChanged(); } /** * This is a great way to set up subcategories for a "sub-tab bar" * using the hidden tabs feature of {@link TabViewPagerFragment} * @param view : the view pager * @param parentTPI : the master tab page indicator, that will likely * have some hidden tabs */ public void setViewPager(ViewPager view, TabPageIndicator parentTPI) { final PagerAdapter adapter = view.getAdapter(); if (adapter == null) { throw new IllegalStateException("ViewPager does not have adapter instance."); } mViewPager = view; mListener2 = parentTPI; view.setOnPageChangeListener(this); notifyDataSetChanged(); setCurrentItem(mViewPager.getCurrentItem()); } @Override public void notifyDataSetChanged() { mTabLayout.removeAllViews(); // for measuring doPreMeasure(); TitleProvider adapter = getTitleProvider(); final int count = adapter.getCount(); for (int i = 0; i < count; i++) { addTab(adapter.getTitle(i), adapter.getIcon(i), i, adapter.isVisible(i)); } if (mSelectedTabIndex > count) { mSelectedTabIndex = count - 1; } setCurrentItemImpl(mSelectedTabIndex); requestLayout(); } /** * Get the {@link TitleProvider} for this tab indicator */ protected TitleProvider getTitleProvider() { return (TitleProvider) mViewPager.getAdapter(); } /** * Does a bit of calculations to better measure the size of tabs. * This is to fix a bug where text would occasionally get cut off. */ private void doPreMeasure() { TabView tabView = (TabView) mInflater.inflate(R.layout.vpi__tab, null); TextView textView = (TextView) tabView.findViewById(android.R.id.text1); ImageView imageView = (ImageView) tabView.findViewById(R.id.img); mTextPaint = textView.getPaint(); mTextPadding = textView.getTotalPaddingLeft() + textView.getTotalPaddingRight() + tabView.getPaddingLeft() + tabView.getPaddingRight(); int mImagePadding = imageView.getPaddingLeft() + imageView.getPaddingRight(); int t = 0; int count = getTitleProvider().getCount(); mAllMinWidths = new int[count]; String text; Drawable d; for (int i = 0; i < count; i++) { d = getTitleProvider().getIcon(i); text = getTitleProvider().getTitle(i); if (d != null) { mAllMinWidths[i] = d.getIntrinsicWidth() + mImagePadding; } else { StaticLayout layout = new StaticLayout(text, mTextPaint, MAX_TAB_WIDTH, Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); int w = (int) (layout.getLineWidth(0) + 1); mAllMinWidths[i] = mTextPadding + w; } if (getTitleProvider().isVisible(i)) t += mAllMinWidths[i]; } mTotalMinWidth = t; } @Override public void setViewPager(ViewPager view, int tab) { setViewPager(view); setCurrentItem(tab); } @Override public void setCurrentItem(int item) { setCurrentItemImpl(item); } /** * Method to set the current item that cannot be overridden * @param item */ private final void setCurrentItemImpl(int item) { if (mViewPager == null) { throw new IllegalStateException("ViewPager has not been bound."); } mSelectedTabIndex = item; final int tabCount = mTabLayout.getChildCount(); View lastVisibleChild = null; int lastVisibleItem = -1; for (int i = 0; i < tabCount; i++) { final View child = mTabLayout.getChildAt(i); if (child.getVisibility() == View.VISIBLE) { lastVisibleChild = child; lastVisibleItem = i; } final boolean isSelected = (i == item); if (lastVisibleChild != null) { if (lastVisibleItem == i || isSelected) { lastVisibleChild.setSelected(isSelected); if (isSelected) animateToTab(lastVisibleItem); } } } } /** * Method called to change the viewpager's pager from the tab indicator, * exposed to allow overriding * @param view : the page index */ protected void setCurrentView(int view) { mViewPager.setCurrentItem(view); } @Override public void setOnPageChangeListener(OnPageChangeListener listener) { mListener = listener; } /** * A short and simple class to represent a tab */ public static class TabView extends LinearLayout { private TabPageIndicator mParent; private int mIndex; public TabView(Context context, AttributeSet attrs) { super(context, attrs); } public void init(TabPageIndicator parent, String text, int index) { mParent = parent; mIndex = index; TextView textView = (TextView) findViewById(android.R.id.text1); textView.setText(text); textView.setVisibility(View.VISIBLE); ImageView imageView = (ImageView) findViewById(R.id.img); imageView.setVisibility(View.GONE); } public void setIcon(Drawable drawable) { TextView textView = (TextView) findViewById(android.R.id.text1); textView.setVisibility(View.GONE); ImageView imageView = (ImageView) findViewById(R.id.img); imageView.setImageDrawable(drawable); imageView.setVisibility(View.VISIBLE); } public void setText(CharSequence txt) { TextView textView = (TextView) findViewById(android.R.id.text1); textView.setVisibility(View.VISIBLE); textView.setText(txt); } @Override public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int minWidth = mParent.mRescaleTabs ? (int) FloatMath.ceil( ((float) mParent.mAllMinWidths[mIndex] / (float) mParent.mTotalMinWidth * mParent.mTargetWidth)) : mParent.mAllMinWidths[mIndex]; // Re-measure if we went beyond our maximum size. if (mParent.mMaxTabWidth > 0 && getMeasuredWidth() > mParent.mMaxTabWidth) { super.onMeasure(MeasureSpec.makeMeasureSpec(mParent.mMaxTabWidth, MeasureSpec.EXACTLY), heightMeasureSpec); } else if (getMeasuredWidth() < minWidth) { super.onMeasure(MeasureSpec.makeMeasureSpec(minWidth, MeasureSpec.EXACTLY), heightMeasureSpec); } } public int getIndex() { return mIndex; } } }