|
/* |
|
/** |
|
* Created by Windows on 16-01-2015. |
|
*/ |
|
/* |
|
* Copyright 2014 Google Inc. All rights reserved. |
|
* |
|
* 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. |
|
*/ |
|
|
|
|
|
import android.content.Context; |
|
import android.content.res.Resources; |
|
import android.graphics.Typeface; |
|
import android.support.v4.view.PagerAdapter; |
|
import android.support.v4.view.ViewPager; |
|
import android.util.AttributeSet; |
|
import android.util.Log; |
|
import android.util.SparseArray; |
|
import android.util.TypedValue; |
|
import android.view.Gravity; |
|
import android.view.LayoutInflater; |
|
import android.view.View; |
|
import android.view.ViewGroup; |
|
import android.widget.HorizontalScrollView; |
|
import android.widget.ImageView; |
|
import android.widget.LinearLayout; |
|
import android.widget.TextView; |
|
|
|
/** |
|
* To be used with ViewPager to provide a tab indicator component which give constant feedback as to |
|
* the user's scroll progress. |
|
* <p> |
|
* To use the component, simply add it to your view hierarchy. Then in your |
|
* {@link android.app.Activity} or {@link android.support.v4.app.Fragment} call |
|
* {@link #setViewPager(ViewPager)} providing it the ViewPager this layout is being used for. |
|
* <p> |
|
* The colors can be customized in two ways. The first and simplest is to provide an array of colors |
|
* via {@link #setSelectedIndicatorColors(int...)}. The |
|
* alternative is via the {@link TabColorizer} interface which provides you complete control over |
|
* which color is used for any individual position. |
|
* <p> |
|
* The views used as tabs can be customized by calling {@link #setCustomTabView(int, int)}, |
|
* providing the layout ID of your custom layout. |
|
*/ |
|
public class SlidingTabLayout extends HorizontalScrollView { |
|
private static final int TITLE_OFFSET_DIPS = 24; |
|
private static final int TAB_VIEW_PADDING_DIPS = 16; |
|
private static final int TAB_VIEW_TEXT_SIZE_SP = 12; |
|
private final SlidingTabStrip mTabStrip; |
|
private int mTitleOffset; |
|
|
|
private int mTabViewSelectedIconColor = 0XFFCCCCCC; |
|
private int mTabViewIconColor = 0XFFCCCCCC; |
|
private int mTabViewSelectedTextColor = 0XFFCCCCCC; |
|
private int mTabViewTextColor = 0XFFCCCCCC; |
|
private int mTabViewLayoutId; |
|
private int mTabViewTextViewId; |
|
private boolean hasIcons = false; |
|
private Integer[] mIconResourceArray; |
|
private boolean mDistributeEvenly; |
|
private int tabPosition = 0; |
|
|
|
private ViewPager mViewPager; |
|
private SparseArray<String> mContentDescriptions = new SparseArray<String>(); |
|
private ViewPager.OnPageChangeListener mViewPagerPageChangeListener; |
|
|
|
public SlidingTabLayout(Context context) { |
|
this(context, null); |
|
} |
|
|
|
public SlidingTabLayout(Context context, AttributeSet attrs) { |
|
this(context, attrs, 0); |
|
} |
|
|
|
public SlidingTabLayout(Context context, AttributeSet attrs, int defStyle) { |
|
super(context, attrs, defStyle); |
|
|
|
// Disable the Scroll Bar |
|
setHorizontalScrollBarEnabled(false); |
|
// Make sure that the Tab Strips fills this View |
|
setFillViewport(true); |
|
|
|
mTitleOffset = (int) (TITLE_OFFSET_DIPS * getResources().getDisplayMetrics().density); |
|
|
|
mTabStrip = new SlidingTabStrip(context); |
|
addView(mTabStrip, LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); |
|
} |
|
|
|
/** |
|
* Set the custom {@link TabColorizer} to be used. |
|
* <p> |
|
* If you only require simple custmisation then you can use |
|
* {@link #setSelectedIndicatorColors(int...)} to achieve |
|
* similar effects. |
|
*/ |
|
public void setCustomTabColorizer(TabColorizer tabColorizer) { |
|
mTabStrip.setCustomTabColorizer(tabColorizer); |
|
} |
|
|
|
public void setDistributeEvenly(boolean distributeEvenly) { |
|
mDistributeEvenly = distributeEvenly; |
|
} |
|
|
|
public void setTabViewSelectedIconColor(int resourceId) { |
|
mTabViewSelectedIconColor = resourceId; |
|
} |
|
|
|
public void setTabViewSelectedTextColor(int resourceId) { |
|
mTabViewSelectedTextColor = resourceId; |
|
} |
|
|
|
public void setTabViewIconColor(int resourceId) { |
|
mTabViewIconColor = resourceId; |
|
} |
|
|
|
public void setTabViewTextColor(int resourceId) { |
|
mTabViewTextColor = resourceId; |
|
} |
|
|
|
/** |
|
* Sets the colors to be used for indicating the selected tab. These colors are treated as a |
|
* circular array. Providing one color will mean that all tabs are indicated with the same color. |
|
*/ |
|
public void setSelectedIndicatorColors(int... colors) { |
|
mTabStrip.setSelectedIndicatorColors(colors); |
|
} |
|
|
|
/** |
|
* Set the {@link ViewPager.OnPageChangeListener}. When using {@link SlidingTabLayout} you are |
|
* required to set any {@link ViewPager.OnPageChangeListener} through this method. This is so |
|
* that the layout can update it's scroll position correctly. |
|
* |
|
* @see ViewPager#setOnPageChangeListener(ViewPager.OnPageChangeListener) |
|
*/ |
|
public void setOnPageChangeListener(ViewPager.OnPageChangeListener listener) { |
|
mViewPagerPageChangeListener = listener; |
|
} |
|
|
|
/** |
|
* Set the custom layout to be inflated for the tab views. |
|
* |
|
* @param layoutResId Layout id to be inflated |
|
* @param textViewId id of the {@link TextView} in the inflated view |
|
*/ |
|
public void setCustomTabView(int layoutResId, int textViewId) { |
|
mTabViewLayoutId = layoutResId; |
|
mTabViewTextViewId = textViewId; |
|
} |
|
|
|
public void hasIcons(boolean hasIcons) { |
|
this.hasIcons = hasIcons; |
|
} |
|
|
|
public Integer[] getIconResourceArray() { |
|
return mIconResourceArray; |
|
} |
|
|
|
public void setIconResourceArray(Integer[] mIconResourceArray) { |
|
this.mIconResourceArray = mIconResourceArray; |
|
} |
|
|
|
/** |
|
* Sets the associated view pager. Note that the assumption here is that the pager content |
|
* (number of tabs and tab titles) does not change after this call has been made. |
|
*/ |
|
public void setViewPager(ViewPager viewPager) { |
|
mTabStrip.removeAllViews(); |
|
|
|
mViewPager = viewPager; |
|
if (viewPager != null) { |
|
viewPager.setOnPageChangeListener(new InternalViewPagerListener()); |
|
populateTabStrip(); |
|
} |
|
} |
|
|
|
/** |
|
* Create a default view to be used for tabs. This is called if a custom tab view is not set via |
|
* {@link #setCustomTabView(int, int)}. |
|
*/ |
|
protected TextView createDefaultTabView(Context context) { |
|
TextView textView = new TextView(context); |
|
textView.setGravity(Gravity.CENTER); |
|
textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, TAB_VIEW_TEXT_SIZE_SP); |
|
textView.setTypeface(Typeface.DEFAULT_BOLD); |
|
textView.setLayoutParams(new LinearLayout.LayoutParams( |
|
ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)); |
|
|
|
TypedValue outValue = new TypedValue(); |
|
getContext().getTheme().resolveAttribute(android.R.attr.selectableItemBackground, |
|
outValue, true); |
|
textView.setBackgroundResource(outValue.resourceId); |
|
textView.setAllCaps(true); |
|
|
|
int padding = (int) (TAB_VIEW_PADDING_DIPS * getResources().getDisplayMetrics().density); |
|
textView.setPadding(padding, padding, padding, padding); |
|
textView.setTextColor(mTabViewTextColor); |
|
return textView; |
|
} |
|
|
|
/** |
|
* Create a default view to be used for tabs. This is called if a custom tab view is not set via |
|
* {@link #setCustomTabView(int, int)}. |
|
*/ |
|
protected LinearLayout createDefaultTabViewWithImage(Context context) { |
|
LinearLayout layout = new LinearLayout(context); |
|
layout.setGravity(Gravity.CENTER); |
|
layout.setLayoutParams(new LinearLayout.LayoutParams( |
|
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); |
|
TypedValue outValue = new TypedValue(); |
|
getContext().getTheme().resolveAttribute(android.R.attr.selectableItemBackground, |
|
outValue, true); |
|
layout.setBackgroundResource(outValue.resourceId); |
|
int padding = (int) (TAB_VIEW_PADDING_DIPS * getResources().getDisplayMetrics().density); |
|
layout.setPadding(padding, padding, padding, padding); |
|
ImageView imageView = new ImageView(context); |
|
imageView.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)); |
|
imageView.setColorFilter(mTabViewIconColor, android.graphics.PorterDuff.Mode.MULTIPLY); |
|
layout.addView(imageView); |
|
return layout; |
|
} |
|
|
|
private void populateTabStrip() { |
|
final PagerAdapter adapter = mViewPager.getAdapter(); |
|
final View.OnClickListener tabClickListener = new TabClickListener(); |
|
try { |
|
if (hasIcons) { |
|
// if title has icons.. |
|
for (int i = 0; i < adapter.getCount(); i++) { |
|
|
|
View tabView = null; |
|
ImageView tabIcons = null; |
|
|
|
if (tabView == null) { |
|
tabView = createDefaultTabViewWithImage(getContext()); |
|
} |
|
|
|
if (tabIcons == null && LinearLayout.class.isInstance(tabView)) { |
|
LinearLayout tabLayout = (LinearLayout) tabView; |
|
tabIcons = (ImageView) tabLayout.getChildAt(0); |
|
} |
|
|
|
if (mDistributeEvenly) { |
|
LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) tabView.getLayoutParams(); |
|
lp.width = 0; |
|
lp.weight = 1; |
|
} |
|
tabIcons.setImageDrawable(getContext().getResources().getDrawable(getIconResourceArray()[i])); |
|
tabView.setOnClickListener(tabClickListener); |
|
String desc = mContentDescriptions.get(i, null); |
|
if (desc != null) { |
|
tabView.setContentDescription(desc); |
|
} |
|
|
|
mTabStrip.addView(tabView); |
|
if (i == mViewPager.getCurrentItem()) { |
|
tabView.setSelected(true); |
|
} |
|
} |
|
} else { |
|
|
|
for (int i = 0; i < adapter.getCount(); i++) { |
|
View tabView = null; |
|
TextView tabTitleView = null; |
|
|
|
if (mTabViewLayoutId != 0) { |
|
// If there is a custom tab view layout id set, try and inflate it |
|
tabView = LayoutInflater.from(getContext()).inflate(mTabViewLayoutId, mTabStrip, |
|
false); |
|
tabTitleView = (TextView) tabView.findViewById(mTabViewTextViewId); |
|
} |
|
|
|
if (tabView == null) { |
|
tabView = createDefaultTabView(getContext()); |
|
} |
|
|
|
if (tabTitleView == null && TextView.class.isInstance(tabView)) { |
|
tabTitleView = (TextView) tabView; |
|
} |
|
|
|
if (mDistributeEvenly) { |
|
LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) tabView.getLayoutParams(); |
|
lp.width = 0; |
|
lp.weight = 1; |
|
} |
|
|
|
tabTitleView.setText(adapter.getPageTitle(i)); |
|
tabView.setOnClickListener(tabClickListener); |
|
String desc = mContentDescriptions.get(i, null); |
|
if (desc != null) { |
|
tabView.setContentDescription(desc); |
|
} |
|
|
|
mTabStrip.addView(tabView); |
|
if (i == mViewPager.getCurrentItem()) { |
|
tabView.setSelected(true); |
|
} |
|
} |
|
} |
|
} catch (Exception e) { |
|
e.printStackTrace(); |
|
} |
|
} |
|
|
|
public void setContentDescription(int i, String desc) { |
|
mContentDescriptions.put(i, desc); |
|
} |
|
|
|
@Override |
|
protected void onAttachedToWindow() { |
|
super.onAttachedToWindow(); |
|
if (mViewPager != null) { |
|
scrollToTab(mViewPager.getCurrentItem(), 0); |
|
} |
|
} |
|
|
|
private void scrollToTab(int tabIndex, int positionOffset) { |
|
final int tabStripChildCount = mTabStrip.getChildCount(); |
|
if (tabStripChildCount == 0 || tabIndex < 0 || tabIndex >= tabStripChildCount) { |
|
return; |
|
} |
|
View selectedChild = mTabStrip.getChildAt(tabIndex); |
|
if (selectedChild != null) { |
|
int targetScrollX = selectedChild.getLeft() + positionOffset; |
|
|
|
if (tabIndex > 0 || positionOffset > 0) { |
|
// If we're not at the first child and are mid-scroll, make sure we obey the offset |
|
targetScrollX -= mTitleOffset; |
|
} |
|
|
|
scrollTo(targetScrollX, 0); |
|
} |
|
} |
|
|
|
/** |
|
* Allows complete control over the colors drawn in the tab layout. Set with |
|
* {@link #setCustomTabColorizer(TabColorizer)}. |
|
*/ |
|
public interface TabColorizer { |
|
|
|
/** |
|
* @return return the color of the indicator used when {@code position} is selected. |
|
*/ |
|
int getIndicatorColor(int position); |
|
|
|
} |
|
|
|
private class InternalViewPagerListener implements ViewPager.OnPageChangeListener { |
|
private int mScrollState; |
|
|
|
@Override |
|
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { |
|
try { |
|
int tabStripChildCount = mTabStrip.getChildCount(); |
|
// Log.d("Sliding tab lib", "position - "+position+", state - 1, Tab Strip Child Count - "+tabStripChildCount); |
|
if ((tabStripChildCount == 0) || (position < 0) || (position >= tabStripChildCount)) { |
|
return; |
|
} |
|
mTabStrip.onViewPagerPageChanged(position, positionOffset); |
|
View selectedTitle = mTabStrip.getChildAt(position); |
|
int extraOffset = (selectedTitle != null) |
|
? (int) (positionOffset * selectedTitle.getWidth()) |
|
: 0; |
|
scrollToTab(position, extraOffset); |
|
if (mViewPagerPageChangeListener != null) { |
|
mViewPagerPageChangeListener.onPageScrolled(position, positionOffset, |
|
positionOffsetPixels); |
|
} |
|
if(hasIcons) { |
|
if ((tabPosition == 0)) { // position = 0,1 |
|
LinearLayout layout = (LinearLayout) mTabStrip.getChildAt(0); |
|
ImageView tabIcon = (ImageView) layout.getChildAt(0); |
|
tabIcon.setColorFilter(mTabViewSelectedIconColor, android.graphics.PorterDuff.Mode.MULTIPLY); |
|
} else { |
|
LinearLayout layout = (LinearLayout) mTabStrip.getChildAt(0); |
|
ImageView tabIcon = (ImageView) layout.getChildAt(0); |
|
tabIcon.setColorFilter(mTabViewIconColor, android.graphics.PorterDuff.Mode.MULTIPLY); |
|
} |
|
} else{ |
|
if ((tabPosition == 0)) { // position = 0,1 |
|
TextView title = (TextView) mTabStrip.getChildAt(0); |
|
title.setTextColor(mTabViewSelectedTextColor); |
|
} else { |
|
TextView title = (TextView) mTabStrip.getChildAt(0); |
|
title.setTextColor(mTabViewTextColor); |
|
} |
|
} |
|
} catch (Exception e) { |
|
e.printStackTrace(); |
|
} |
|
} |
|
|
|
@Override |
|
public void onPageScrollStateChanged(int state) { |
|
mScrollState = state; |
|
|
|
if (mViewPagerPageChangeListener != null) { |
|
mViewPagerPageChangeListener.onPageScrollStateChanged(state); |
|
} |
|
} |
|
|
|
@Override |
|
public void onPageSelected(int position) { |
|
try { |
|
if (mScrollState == ViewPager.SCROLL_STATE_IDLE) { |
|
mTabStrip.onViewPagerPageChanged(position, 0f); |
|
scrollToTab(position, 0); |
|
} |
|
for (int i = 0; i < mTabStrip.getChildCount(); i++) { |
|
mTabStrip.getChildAt(i).setSelected(position == i); |
|
if (hasIcons) { |
|
if((position == i)){ // position = 0,1 |
|
tabPosition = position; |
|
LinearLayout layout = (LinearLayout) mTabStrip.getChildAt(i); |
|
ImageView tabIcon = (ImageView) layout.getChildAt(0); |
|
tabIcon.setColorFilter(mTabViewSelectedIconColor, android.graphics.PorterDuff.Mode.MULTIPLY); |
|
} else{ |
|
LinearLayout layout = (LinearLayout) mTabStrip.getChildAt(i); |
|
ImageView tabIcon = (ImageView) layout.getChildAt(0); |
|
tabIcon.setColorFilter(mTabViewIconColor, android.graphics.PorterDuff.Mode.MULTIPLY); |
|
} |
|
} else { |
|
if((position == i)){ // position = 0,1 |
|
tabPosition = position; |
|
TextView title = (TextView) mTabStrip.getChildAt(i); |
|
title.setTextColor(mTabViewSelectedTextColor); |
|
} else{ |
|
TextView title = (TextView) mTabStrip.getChildAt(i); |
|
title.setTextColor(mTabViewTextColor); |
|
} |
|
} |
|
} |
|
if (mViewPagerPageChangeListener != null) { |
|
mViewPagerPageChangeListener.onPageSelected(position); |
|
} |
|
} catch (Exception e) { |
|
e.printStackTrace(); |
|
} |
|
} |
|
|
|
} |
|
|
|
private class TabClickListener implements View.OnClickListener { |
|
@Override |
|
public void onClick(View v) { |
|
for (int i = 0; i < mTabStrip.getChildCount(); i++) { |
|
if (v == mTabStrip.getChildAt(i)) { |
|
mViewPager.setCurrentItem(i); |
|
return; |
|
} |
|
} |
|
} |
|
} |
|
|
|
} |
((ImageView) ((LinearLayout) mTabStrip.getChildAt(i)).getChildAt(0)).setColorFilter(i == position ? mTabViewSelectedIconColor : mTabViewIconColor,android.graphics.PorterDuff.Mode.MULTIPLY);