Android Open Source - Resonos-Android-Framework Tab Page Indicator






From Project

Back to project page Resonos-Android-Framework.

License

The source code is released under:

Apache License

If you think the Android project Resonos-Android-Framework listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

/*
 * Copyright (C) 2011 The Android Open Source Project
 * Copyright (C) 2011 Jake Wharton//w w w.  ja  v  a 2  s . c  o  m
 *
 * 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;
        }
    }
}




Java Source Code List

com.resonos.apps.library.Action.java
com.resonos.apps.library.AlertFragment.java
com.resonos.apps.library.App.java
com.resonos.apps.library.BaseFragment.java
com.resonos.apps.library.FragmentBaseActivity.java
com.resonos.apps.library.file.AltAndroidFileHandle.java
com.resonos.apps.library.file.AltAndroidFiles.java
com.resonos.apps.library.file.AltFileHandle.java
com.resonos.apps.library.file.FileCache.java
com.resonos.apps.library.media.AudioVisualizer.java
com.resonos.apps.library.media.BitmapMemoryCache.java
com.resonos.apps.library.media.HueColorFilter.java
com.resonos.apps.library.media.ImageLoader.java
com.resonos.apps.library.media.MediaScannerNotifier.java
com.resonos.apps.library.model.Coord.java
com.resonos.apps.library.model.ImmutableCoord.java
com.resonos.apps.library.tabviewpager.CustomViewPager.java
com.resonos.apps.library.tabviewpager.PageIndicator.java
com.resonos.apps.library.tabviewpager.TabPageIndicator.java
com.resonos.apps.library.tabviewpager.TabViewPagerAdapter.java
com.resonos.apps.library.tabviewpager.TabViewPagerFragment.java
com.resonos.apps.library.tabviewpager.TitleProvider.java
com.resonos.apps.library.util.AppUtils.java
com.resonos.apps.library.util.ErrorReporter.java
com.resonos.apps.library.util.LifecycleTaskQueue.java
com.resonos.apps.library.util.M.java
com.resonos.apps.library.util.NetworkClient.java
com.resonos.apps.library.util.NetworkRequest.java
com.resonos.apps.library.util.ParameterList.java
com.resonos.apps.library.util.SensorReader.java
com.resonos.apps.library.util.TouchViewWorker.java
com.resonos.apps.library.util.ViewServer.java
com.resonos.apps.library.widget.DashboardLayout.java
com.resonos.apps.library.widget.FormBuilder.java
com.resonos.apps.library.widget.FormElement.java
com.resonos.apps.library.widget.ListFormBuilder.java
com.resonos.apps.library.widget.PopupWindows3D.java
com.resonos.apps.library.widget.QuickAction3D.java
com.resonos.apps.library.widget.RangeSeekBar.java
com.resonos.apps.library.widget.SeekBar.java
com.resonos.apps.library.widget.ToolBarButton.java
com.resonos.apps.library.widget.ToolBar.java