package com.sxjs.common.widget.bottomnavigation;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.os.Build;
import android.support.annotation.ColorRes;
import android.support.annotation.IntDef;
import android.support.design.widget.CoordinatorLayout;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.content.ContextCompat;
import android.support.v4.view.ViewCompat;
import android.support.v4.view.ViewPropertyAnimatorCompat;
import android.support.v4.view.animation.LinearOutSlowInInterpolator;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewOutlineProvider;
import android.view.animation.Interpolator;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import com.sxjs.common.R;
import com.sxjs.common.widget.bottomnavigation.behaviour.BottomNavBarFabBehaviour;
import com.sxjs.common.widget.bottomnavigation.behaviour.BottomVerticalScrollBehavior;
import com.sxjs.common.widget.bottomnavigation.utils.Utils;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
/**
* Class description : This class is used to draw the layout and this acts like a bridge between
* library and app, all details can be modified via this class.
*
* @author ashokvarma
* @version 1.0
* @see FrameLayout
* @see <a href="https://www.google.com/design/spec/components/bottom-navigation.html">Google Bottom Navigation Component</a>
* @since 19 Mar 2016
*/
@CoordinatorLayout.DefaultBehavior(BottomVerticalScrollBehavior.class)
public class BottomNavigationBar extends FrameLayout {
public static final int MODE_DEFAULT = 0;
public static final int MODE_FIXED = 1;
public static final int MODE_SHIFTING = 2;
@IntDef({MODE_DEFAULT, MODE_FIXED, MODE_SHIFTING})
@Retention(RetentionPolicy.SOURCE)
public @interface Mode {
}
public static final int BACKGROUND_STYLE_DEFAULT = 0;
public static final int BACKGROUND_STYLE_STATIC = 1;
public static final int BACKGROUND_STYLE_RIPPLE = 2;
@IntDef({BACKGROUND_STYLE_DEFAULT, BACKGROUND_STYLE_STATIC, BACKGROUND_STYLE_RIPPLE})
@Retention(RetentionPolicy.SOURCE)
public @interface BackgroundStyle {
}
private static final int FAB_BEHAVIOUR_TRANSLATE_AND_STICK = 0;
private static final int FAB_BEHAVIOUR_DISAPPEAR = 1;
private static final int FAB_BEHAVIOUR_TRANSLATE_OUT = 2;
@IntDef({FAB_BEHAVIOUR_TRANSLATE_AND_STICK, FAB_BEHAVIOUR_DISAPPEAR, FAB_BEHAVIOUR_TRANSLATE_OUT})
@Retention(RetentionPolicy.SOURCE)
public @interface FabBehaviour {
}
@Mode
private int mMode = MODE_DEFAULT;
@BackgroundStyle
private int mBackgroundStyle = BACKGROUND_STYLE_DEFAULT;
private static final Interpolator INTERPOLATOR = new LinearOutSlowInInterpolator();
private ViewPropertyAnimatorCompat mTranslationAnimator;
private boolean mScrollable = false;
private static final int MIN_SIZE = 3;
private static final int MAX_SIZE = 5;
ArrayList<BottomNavigationItem> mBottomNavigationItems = new ArrayList<>();
ArrayList<BottomNavigationTab> mBottomNavigationTabs = new ArrayList<>();
private static final int DEFAULT_SELECTED_POSITION = -1;
private int mSelectedPosition = DEFAULT_SELECTED_POSITION;
private int mFirstSelectedPosition = 0;
private OnTabSelectedListener mTabSelectedListener;
private int mActiveColor;
private int mInActiveColor;
private int mBackgroundColor;
private FrameLayout mBackgroundOverlay;
private FrameLayout mContainer;
private LinearLayout mTabContainer;
private static final int DEFAULT_ANIMATION_DURATION = 200;
private int mAnimationDuration = DEFAULT_ANIMATION_DURATION;
private int mRippleAnimationDuration = (int) (DEFAULT_ANIMATION_DURATION * 2.5);
private float mElevation;
private boolean mAutoHideEnabled;
private boolean mIsHidden = false;
///////////////////////////////////////////////////////////////////////////
// View Default Constructors and Methods
///////////////////////////////////////////////////////////////////////////
public BottomNavigationBar(Context context) {
this(context, null);
}
public BottomNavigationBar(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public BottomNavigationBar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
parseAttrs(context, attrs);
init();
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public BottomNavigationBar(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
parseAttrs(context, attrs);
init();
}
/**
* This method initiates the bottomNavigationBar properties,
* Tries to get them form XML if not preset sets them to their default values.
*
* @param context context of the bottomNavigationBar
* @param attrs attributes mentioned in the layout XML by user
*/
private void parseAttrs(Context context, AttributeSet attrs) {
if (attrs != null) {
TypedArray typedArray = context.getTheme().obtainStyledAttributes(attrs, R.styleable.BottomNavigationBar, 0, 0);
mActiveColor = typedArray.getColor(R.styleable.BottomNavigationBar_bnbActiveColor, Utils.fetchContextColor(context, R.attr.colorAccent));
mInActiveColor = typedArray.getColor(R.styleable.BottomNavigationBar_bnbInactiveColor, Color.LTGRAY);
mBackgroundColor = typedArray.getColor(R.styleable.BottomNavigationBar_bnbBackgroundColor, Color.WHITE);
mAutoHideEnabled = typedArray.getBoolean(R.styleable.BottomNavigationBar_bnbAutoHideEnabled, true);
mElevation = typedArray.getDimension(R.styleable.BottomNavigationBar_bnbElevation, getResources().getDimension(R.dimen.bottom_navigation_elevation));
setAnimationDuration(typedArray.getInt(R.styleable.BottomNavigationBar_bnbAnimationDuration, DEFAULT_ANIMATION_DURATION));
switch (typedArray.getInt(R.styleable.BottomNavigationBar_bnbMode, MODE_DEFAULT)) {
case MODE_FIXED:
mMode = MODE_FIXED;
break;
case MODE_SHIFTING:
mMode = MODE_SHIFTING;
break;
case MODE_DEFAULT:
default:
mMode = MODE_DEFAULT;
break;
}
switch (typedArray.getInt(R.styleable.BottomNavigationBar_bnbBackgroundStyle, BACKGROUND_STYLE_DEFAULT)) {
case BACKGROUND_STYLE_STATIC:
mBackgroundStyle = BACKGROUND_STYLE_STATIC;
break;
case BACKGROUND_STYLE_RIPPLE:
mBackgroundStyle = BACKGROUND_STYLE_RIPPLE;
break;
case BACKGROUND_STYLE_DEFAULT:
default:
mBackgroundStyle = BACKGROUND_STYLE_DEFAULT;
break;
}
typedArray.recycle();
} else {
mActiveColor = Utils.fetchContextColor(context, R.attr.colorAccent);
mInActiveColor = Color.LTGRAY;
mBackgroundColor = Color.WHITE;
mElevation = getResources().getDimension(R.dimen.bottom_navigation_elevation);
}
}
/**
* This method initiates the bottomNavigationBar and handles layout related values
*/
private void init() {
// MarginLayoutParams marginParams = new ViewGroup.MarginLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, (int) getContext().getResources().getDimension(R.dimen.bottom_navigation_padded_height)));
// marginParams.setMargins(0, (int) getContext().getResources().getDimension(R.dimen.bottom_navigation_top_margin_correction), 0, 0);
setLayoutParams(new ViewGroup.LayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)));
LayoutInflater inflater = LayoutInflater.from(getContext());
View parentView = inflater.inflate(R.layout.bottom_navigation_bar_container, this, true);
mBackgroundOverlay = (FrameLayout) parentView.findViewById(R.id.bottom_navigation_bar_overLay);
mContainer = (FrameLayout) parentView.findViewById(R.id.bottom_navigation_bar_container);
mTabContainer = (LinearLayout) parentView.findViewById(R.id.bottom_navigation_bar_item_container);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
this.setOutlineProvider(ViewOutlineProvider.BOUNDS);
} else {
//to do
}
ViewCompat.setElevation(this, mElevation);
setClipToPadding(false);
}
// @Override
// protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// }
///////////////////////////////////////////////////////////////////////////
// View Data Setter methods, Called before Initialize method
///////////////////////////////////////////////////////////////////////////
/**
* Used to add a new tab.
*
* @param item bottom navigation tab details
* @return this, to allow builder pattern
*/
public BottomNavigationBar addItem(BottomNavigationItem item) {
mBottomNavigationItems.add(item);
return this;
}
/**
* Used to remove a tab.
* you should call initialise() after this to see the results effected.
*
* @param item bottom navigation tab details
* @return this, to allow builder pattern
*/
public BottomNavigationBar removeItem(BottomNavigationItem item) {
mBottomNavigationItems.remove(item);
return this;
}
/**
* @param mode any of the three Modes supported by library
* @return this, to allow builder pattern
*/
public BottomNavigationBar setMode(@Mode int mode) {
this.mMode = mode;
return this;
}
/**
* @param backgroundStyle any of the three Background Styles supported by library
* @return this, to allow builder pattern
*/
public BottomNavigationBar setBackgroundStyle(@BackgroundStyle int backgroundStyle) {
this.mBackgroundStyle = backgroundStyle;
return this;
}
/**
* @param activeColor res code for the default active color
* @return this, to allow builder pattern
*/
public BottomNavigationBar setActiveColor(@ColorRes int activeColor) {
this.mActiveColor = ContextCompat.getColor(getContext(), activeColor);
return this;
}
/**
* @param activeColorCode color code in string format for the default active color
* @return this, to allow builder pattern
*/
public BottomNavigationBar setActiveColor(String activeColorCode) {
this.mActiveColor = Color.parseColor(activeColorCode);
return this;
}
/**
* @param inActiveColor res code for the default in-active color
* @return this, to allow builder pattern
*/
public BottomNavigationBar setInActiveColor(@ColorRes int inActiveColor) {
this.mInActiveColor = ContextCompat.getColor(getContext(), inActiveColor);
return this;
}
/**
* @param inActiveColorCode color code in string format for the default in-active color
* @return this, to allow builder pattern
*/
public BottomNavigationBar setInActiveColor(String inActiveColorCode) {
this.mInActiveColor = Color.parseColor(inActiveColorCode);
return this;
}
/**
* @param backgroundColor res code for the default background color
* @return this, to allow builder pattern
*/
public BottomNavigationBar setBarBackgroundColor(@ColorRes int backgroundColor) {
this.mBackgroundColor = ContextCompat.getColor(getContext(), backgroundColor);
return this;
}
/**
* @param backgroundColorCode color code in string format for the default background color
* @return this, to allow builder pattern
*/
public BottomNavigationBar setBarBackgroundColor(String backgroundColorCode) {
this.mBackgroundColor = Color.parseColor(backgroundColorCode);
return this;
}
/**
* @param firstSelectedPosition position of tab that needs to be selected by default
* @return this, to allow builder pattern
*/
public BottomNavigationBar setFirstSelectedPosition(int firstSelectedPosition) {
this.mFirstSelectedPosition = firstSelectedPosition;
return this;
}
/**
* will be public once all bugs are ressolved.
*/
private BottomNavigationBar setScrollable(boolean scrollable) {
mScrollable = scrollable;
return this;
}
///////////////////////////////////////////////////////////////////////////
// Initialise Method
///////////////////////////////////////////////////////////////////////////
/**
* This method should be called at the end of all customisation method.
* This method will take all changes in to consideration and redraws tabs.
*/
public void initialise() {
mSelectedPosition = DEFAULT_SELECTED_POSITION;
mBottomNavigationTabs.clear();
if (!mBottomNavigationItems.isEmpty()) {
mTabContainer.removeAllViews();
if (mMode == MODE_DEFAULT) {
if (mBottomNavigationItems.size() <= MIN_SIZE) {
mMode = MODE_FIXED;
} else {
mMode = MODE_SHIFTING;
}
}
if (mBackgroundStyle == BACKGROUND_STYLE_DEFAULT) {
if (mMode == MODE_FIXED) {
mBackgroundStyle = BACKGROUND_STYLE_STATIC;
} else {
mBackgroundStyle = BACKGROUND_STYLE_RIPPLE;
}
}
if (mBackgroundStyle == BACKGROUND_STYLE_STATIC) {
mBackgroundOverlay.setVisibility(View.GONE);
mContainer.setBackgroundColor(mBackgroundColor);
}
int screenWidth = Utils.getScreenWidth(getContext());
if (mMode == MODE_FIXED) {
int[] widths = BottomNavigationHelper.getMeasurementsForFixedMode(getContext(), screenWidth, mBottomNavigationItems.size(), mScrollable);
int itemWidth = widths[0];
for (BottomNavigationItem currentItem : mBottomNavigationItems) {
FixedBottomNavigationTab bottomNavigationTab = new FixedBottomNavigationTab(getContext());
setUpTab(bottomNavigationTab, currentItem, itemWidth, itemWidth);
}
} else if (mMode == MODE_SHIFTING) {
int[] widths = BottomNavigationHelper.getMeasurementsForShiftingMode(getContext(), screenWidth, mBottomNavigationItems.size(), mScrollable);
int itemWidth = widths[0];
int itemActiveWidth = widths[1];
for (BottomNavigationItem currentItem : mBottomNavigationItems) {
ShiftingBottomNavigationTab bottomNavigationTab = new ShiftingBottomNavigationTab(getContext());
setUpTab(bottomNavigationTab, currentItem, itemWidth, itemActiveWidth);
}
}
if (mBottomNavigationTabs.size() > mFirstSelectedPosition) {
selectTabInternal(mFirstSelectedPosition, true, false, false);
} else if (!mBottomNavigationTabs.isEmpty()) {
selectTabInternal(0, true, false, false);
}
}
}
////////////////////////////////////////////////////////////////////////////////////////////////
// Anytime Setter methods that can be called irrespective of whether we call initialise or not
////////////////////////////////////////////////////////////////////////////////////////////////
/**
* @param tabSelectedListener callback listener for tabs
* @return this, to allow builder pattern
*/
public BottomNavigationBar setTabSelectedListener(OnTabSelectedListener tabSelectedListener) {
this.mTabSelectedListener = tabSelectedListener;
return this;
}
/**
* ripple animation will be 2.5 times this animation duration.
*
* @param animationDuration animation duration for tab animations
* @return this, to allow builder pattern
*/
public BottomNavigationBar setAnimationDuration(int animationDuration) {
this.mAnimationDuration = animationDuration;
this.mRippleAnimationDuration = (int) (animationDuration * 2.5);
return this;
}
/**
* Clears all stored data and this helps to re-initialise tabs from scratch
*/
public void clearAll() {
mTabContainer.removeAllViews();
mBottomNavigationTabs.clear();
mBottomNavigationItems.clear();
mBackgroundOverlay.setVisibility(View.GONE);
mContainer.setBackgroundColor(Color.TRANSPARENT);
mSelectedPosition = DEFAULT_SELECTED_POSITION;
}
///////////////////////////////////////////////////////////////////////////
// Setter methods that should called only after initialise is called
///////////////////////////////////////////////////////////////////////////
/**
* Should be called only after initialization of BottomBar(i.e after calling initialize method)
*
* @param newPosition to select a tab after bottom navigation bar is initialised
*/
public void selectTab(int newPosition) {
selectTab(newPosition, true);
}
/**
* Should be called only after initialization of BottomBar(i.e after calling initialize method)
*
* @param newPosition to select a tab after bottom navigation bar is initialised
* @param callListener should this change call listener callbacks
*/
public void selectTab(int newPosition, boolean callListener) {
selectTabInternal(newPosition, false, callListener, callListener);
}
///////////////////////////////////////////////////////////////////////////
// Internal Methods of the class
///////////////////////////////////////////////////////////////////////////
/**
* Internal method to setup tabs
*
* @param bottomNavigationTab Tab item
* @param currentItem data structure for tab item
* @param itemWidth tab item in-active width
* @param itemActiveWidth tab item active width
*/
private void setUpTab(BottomNavigationTab bottomNavigationTab, BottomNavigationItem currentItem, int itemWidth, int itemActiveWidth) {
bottomNavigationTab.setInactiveWidth(itemWidth);
bottomNavigationTab.setActiveWidth(itemActiveWidth);
bottomNavigationTab.setPosition(mBottomNavigationItems.indexOf(currentItem));
bottomNavigationTab.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
BottomNavigationTab bottomNavigationTabView = (BottomNavigationTab) v;
selectTabInternal(bottomNavigationTabView.getPosition(), false, true, false);
}
});
mBottomNavigationTabs.add(bottomNavigationTab);
BottomNavigationHelper.bindTabWithData(currentItem, bottomNavigationTab, this);
bottomNavigationTab.initialise(mBackgroundStyle == BACKGROUND_STYLE_STATIC);
mTabContainer.addView(bottomNavigationTab);
}
/**
* Internal Method to select a tab
*
* @param newPosition to select a tab after bottom navigation bar is initialised
* @param firstTab if firstTab the no ripple animation will be done
* @param callListener is listener callbacks enabled for this change
* @param forcedSelection if bottom navigation bar forced to select tab (in this case call on selected irrespective of previous state
*/
private void selectTabInternal(int newPosition, boolean firstTab, boolean callListener, boolean forcedSelection) {
int oldPosition = mSelectedPosition;
if (mSelectedPosition != newPosition) {
if (mBackgroundStyle == BACKGROUND_STYLE_STATIC) {
if (mSelectedPosition != -1)
mBottomNavigationTabs.get(mSelectedPosition).unSelect(true, mAnimationDuration);
mBottomNavigationTabs.get(newPosition).select(true, mAnimationDuration);
} else if (mBackgroundStyle == BACKGROUND_STYLE_RIPPLE) {
if (mSelectedPosition != -1)
mBottomNavigationTabs.get(mSelectedPosition).unSelect(false, mAnimationDuration);
mBottomNavigationTabs.get(newPosition).select(false, mAnimationDuration);
final BottomNavigationTab clickedView = mBottomNavigationTabs.get(newPosition);
if (firstTab) {
// Running a ripple on the opening app won't be good so on firstTab this won't run.
mContainer.setBackgroundColor(clickedView.getActiveColor());
mBackgroundOverlay.setVisibility(View.GONE);
} else {
mBackgroundOverlay.post(new Runnable() {
@Override
public void run() {
// try {
BottomNavigationHelper.setBackgroundWithRipple(clickedView, mContainer, mBackgroundOverlay, clickedView.getActiveColor(), mRippleAnimationDuration);
// } catch (Exception e) {
// mContainer.setBackgroundColor(clickedView.getActiveColor());
// mBackgroundOverlay.setVisibility(View.GONE);
// }
}
});
}
}
mSelectedPosition = newPosition;
}
if (callListener) {
sendListenerCall(oldPosition, newPosition, forcedSelection);
}
}
/**
* Internal method used to send callbacks to listener
*
* @param oldPosition old selected tab position, -1 if this is first call
* @param newPosition newly selected tab position
* @param forcedSelection if bottom navigation bar forced to select tab (in this case call on selected irrespective of previous state
*/
private void sendListenerCall(int oldPosition, int newPosition, boolean forcedSelection) {
if (mTabSelectedListener != null) {
// && oldPosition != -1) {
if (forcedSelection) {
mTabSelectedListener.onTabSelected(newPosition);
} else {
if (oldPosition == newPosition) {
mTabSelectedListener.onTabReselected(newPosition);
} else {
mTabSelectedListener.onTabSelected(newPosition);
if (oldPosition != -1) {
mTabSelectedListener.onTabUnselected(oldPosition);
}
}
}
}
}
///////////////////////////////////////////////////////////////////////////
// Animating methods
///////////////////////////////////////////////////////////////////////////
/**
* show BottomNavigationBar if it is hidden and hide if it is shown
*/
public void toggle() {
toggle(true);
}
/**
* show BottomNavigationBar if it is hidden and hide if it is shown
*
* @param animate is animation enabled for toggle
*/
public void toggle(boolean animate) {
if (mIsHidden) {
show(animate);
} else {
hide(animate);
}
}
/**
* hide with animation
*/
public void hide() {
hide(true);
}
/**
* @param animate is animation enabled for hide
*/
public void hide(boolean animate) {
mIsHidden = true;
setTranslationY(this.getHeight(), animate);
}
/**
* show with animation
*/
public void show() {
show(true);
}
/**
* @param animate is animation enabled for show
*/
public void show(boolean animate) {
mIsHidden = false;
setTranslationY(0, animate);
}
/**
* @param offset offset needs to be set
* @param animate is animation enabled for translation
*/
private void setTranslationY(int offset, boolean animate) {
if (animate) {
animateOffset(offset);
} else {
if (mTranslationAnimator != null) {
mTranslationAnimator.cancel();
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
this.setTranslationY(offset);
}
}
}
/**
* Internal Method
* <p>
* used to set animation and
* takes care of cancelling current animation
* and sets duration and interpolator for animation
*
* @param offset translation offset that needs to set with animation
*/
private void animateOffset(final int offset) {
if (mTranslationAnimator == null) {
mTranslationAnimator = ViewCompat.animate(this);
mTranslationAnimator.setDuration(mRippleAnimationDuration);
mTranslationAnimator.setInterpolator(INTERPOLATOR);
} else {
mTranslationAnimator.cancel();
}
mTranslationAnimator.translationY(offset).start();
}
public boolean isHidden() {
return mIsHidden;
}
///////////////////////////////////////////////////////////////////////////
// Behaviour Handing Handling
///////////////////////////////////////////////////////////////////////////
public boolean isAutoHideEnabled() {
return mAutoHideEnabled;
}
public void setAutoHideEnabled(boolean mAutoHideEnabled) {
this.mAutoHideEnabled = mAutoHideEnabled;
}
public void setFab(FloatingActionButton fab) {
ViewGroup.LayoutParams layoutParams = fab.getLayoutParams();
if (layoutParams != null && layoutParams instanceof CoordinatorLayout.LayoutParams) {
CoordinatorLayout.LayoutParams coLayoutParams = (CoordinatorLayout.LayoutParams) layoutParams;
BottomNavBarFabBehaviour bottomNavBarFabBehaviour = new BottomNavBarFabBehaviour();
coLayoutParams.setBehavior(bottomNavBarFabBehaviour);
}
}
// scheduled for next
private void setFab(FloatingActionButton fab, @FabBehaviour int fabBehaviour) {
ViewGroup.LayoutParams layoutParams = fab.getLayoutParams();
if (layoutParams != null && layoutParams instanceof CoordinatorLayout.LayoutParams) {
CoordinatorLayout.LayoutParams coLayoutParams = (CoordinatorLayout.LayoutParams) layoutParams;
BottomNavBarFabBehaviour bottomNavBarFabBehaviour = new BottomNavBarFabBehaviour();
coLayoutParams.setBehavior(bottomNavBarFabBehaviour);
}
}
///////////////////////////////////////////////////////////////////////////
// Getters
///////////////////////////////////////////////////////////////////////////
/**
* @return activeColor
*/
public int getActiveColor() {
return mActiveColor;
}
/**
* @return in-active color
*/
public int getInActiveColor() {
return mInActiveColor;
}
/**
* @return background color
*/
public int getBackgroundColor() {
return mBackgroundColor;
}
/**
* @return current selected position
*/
public int getCurrentSelectedPosition() {
return mSelectedPosition;
}
/**
* @return animation duration
*/
public int getAnimationDuration() {
return mAnimationDuration;
}
///////////////////////////////////////////////////////////////////////////
// Listener interfaces
///////////////////////////////////////////////////////////////////////////
/**
* Callback interface invoked when a tab's selection state changes.
*/
public interface OnTabSelectedListener {
/**
* Called when a tab enters the selected state.
*
* @param position The position of the tab that was selected
*/
void onTabSelected(int position);
/**
* Called when a tab exits the selected state.
*
* @param position The position of the tab that was unselected
*/
void onTabUnselected(int position);
/**
* Called when a tab that is already selected is chosen again by the user. Some applications
* may use this action to return to the top level of a category.
*
* @param position The position of the tab that was reselected.
*/
void onTabReselected(int position);
}
/**
* Simple implementation of the OnTabSelectedListener interface with stub implementations of each method.
* Extend this if you do not intend to override every method of OnTabSelectedListener.
*/
public static class SimpleOnTabSelectedListener implements OnTabSelectedListener {
@Override
public void onTabSelected(int position) {
}
@Override
public void onTabUnselected(int position) {
}
@Override
public void onTabReselected(int position) {
}
}
}