Skip to content

Instantly share code, notes, and snippets.

@aldoborrero
Created May 13, 2014 22:09
Show Gist options
  • Save aldoborrero/70fbeb062fab0ccc7d87 to your computer and use it in GitHub Desktop.
Save aldoborrero/70fbeb062fab0ccc7d87 to your computer and use it in GitHub Desktop.
A quick and dirty (very dirty indeed) FixedIconTabPagerIndicator which includes an Icon and a little text!
/**
* This widget implements an indicator that mimics those found
* in iOS.
*/
public class FixedIconTabPageIndicator extends LinearLayout implements PageIndicator {
public static final String TAG = FixedIconTabPageIndicator.class.getSimpleName();
private static final CharSequence DEFAULT_EMPTY_TITLE = "";
private static final int DEFAULT_ANIM_TIME = 250;
private int mMaxTabWidth;
private int mSelectedTabIndex;
private ViewPager mViewPager;
private ViewPager.OnPageChangeListener mListener;
private Runnable mTabSelector;
//PageIndicator Footer required Views
private View[] barViews;
private View pageIndicatorEmptySpace;
private boolean gapOpen;
private final OnClickListener mTabClickListener = new OnClickListener() {
public void onClick(View view) {
//TabView tabView = (TabView) view;
TabLinearView tabView = (TabLinearView) view;
final int oldSelected = mViewPager.getCurrentItem();
final int newSelected = tabView.getIndex();
//Use array of views
for (int i = 0; i < barViews.length; i++) {
if (i == newSelected)
barViews[i].setBackgroundColor(Color.RED);
else
barViews[i].setBackgroundColor(Color.TRANSPARENT);
}
mViewPager.setCurrentItem(newSelected);
if (oldSelected == newSelected && mTabReselectedListener != null) {
mTabReselectedListener.onTabReselected(newSelected);
}
}
};
private OnTabReselectedListener mTabReselectedListener;
/**
* Interface for a callback when the selected tab has been reselected.
*/
public interface OnTabReselectedListener {
/**
* Callback when the selected tab has been reselected.
*
* @param position Position of the current center item.
*/
void onTabReselected(int position);
}
public FixedIconTabPageIndicator(Context context) {
this(context, null);
}
public FixedIconTabPageIndicator(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public FixedIconTabPageIndicator(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setHorizontalGravity(LinearLayout.HORIZONTAL);
}
@Override
public void onAttachedToWindow() {
super.onAttachedToWindow();
if (mTabSelector != null) {
post(mTabSelector);
}
}
@Override
public void onDetachedFromWindow() {
super.onDetachedFromWindow();
if (mTabSelector != null) {
removeCallbacks(mTabSelector);
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
public void setViewPager(ViewPager view) {
if (mViewPager == view) {
return;
}
if (mViewPager != null) {
mViewPager.setOnPageChangeListener(null);
}
final PagerAdapter adapter = view.getAdapter();
if (adapter == null) {
throw new IllegalStateException("ViewPager does not have adapter instance.");
}
mViewPager = view;
view.setOnPageChangeListener(this);
notifyDataSetChanged();
}
@Override
public void setViewPager(ViewPager view, int initialPosition) {
setViewPager(view);
setCurrentItem(initialPosition);
}
@Override
public void setCurrentItem(int item) {
if (mViewPager == null) {
throw new IllegalStateException("ViewPager has not been bound.");
}
mSelectedTabIndex = item;
mViewPager.setCurrentItem(item);
final int tabCount = getChildCount();
for (int i = 0; i < tabCount; i++) {
final View child = getChildAt(i);
final boolean isSelected = (i == item);
child.setSelected(isSelected);
if (isSelected) {
animateToTab(item);
}
}
}
@Override
public void setOnPageChangeListener(ViewPager.OnPageChangeListener listener) {
mListener = listener;
}
@Override
public void notifyDataSetChanged() {
removeAllViews();
PagerAdapter adapter = mViewPager.getAdapter();
IconPagerAdapter iconAdapter = null;
if (adapter instanceof IconPagerAdapter) {
iconAdapter = (IconPagerAdapter) adapter;
}
int count = adapter.getCount();
barViews = new View[count];
boolean emptyTabAdded = false;
for (int i = 0; i < count; i++) {
if (!emptyTabAdded && i == count / 2) { //Center of the indicator
emptyTabAdded = true;
addEmptyTab();
i--; //Ignore this step on the bucle
} else {
CharSequence title = adapter.getPageTitle(i);
if (title == null) {
title = DEFAULT_EMPTY_TITLE;
}
int iconResId = 0;
if (iconAdapter != null) {
iconResId = iconAdapter.getIconResId(i);
}
addTab(i, title, iconResId);
}
}
count++;
if (mSelectedTabIndex > count) {
mSelectedTabIndex = count - 1;
}
setCurrentItem(mSelectedTabIndex);
requestLayout();
}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
if (mListener != null) {
mListener.onPageScrolled(position, positionOffset, positionOffsetPixels);
}
}
@Override
public void onPageSelected(int position) {
setCurrentItem(position);
if (mListener != null) {
mListener.onPageSelected(position);
}
}
@Override
public void onPageScrollStateChanged(int state) {
if (mListener != null) {
mListener.onPageScrollStateChanged(state);
}
}
public void setOnTabReselectedListener(OnTabReselectedListener listener) {
mTabReselectedListener = listener;
}
private void addEmptyTab() {
final TabLinearView tabView = new TabLinearView(getContext());
pageIndicatorEmptySpace = tabView; //Store the middle view in attribute
addView(tabView, new LinearLayout.LayoutParams(0, MATCH_PARENT));
}
private void addTab(int index, CharSequence text, int iconResId) {
final TabLinearView tabView = new TabLinearView(getContext());
tabView.setIndex(index);
tabView.setFocusable(true);
tabView.setOnClickListener(mTabClickListener);
ImageView imgIconIndicator = new ImageView(getContext());
imgIconIndicator.setImageDrawable(getResources().getDrawable(iconResId));
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(dpToPx(35), dpToPx(35));
params.gravity = Gravity.CENTER;
imgIconIndicator.setLayoutParams(params);
imgIconIndicator.setPadding(dpToPx(4), dpToPx(4), dpToPx(4), 0);
tabView.addView(imgIconIndicator);
TextView txtIconIndicator = new TextView(getContext());
txtIconIndicator.setText(text);
txtIconIndicator.setTextSize(12);
txtIconIndicator.setTextColor(Color.BLACK);
txtIconIndicator.setGravity(Gravity.CENTER);
txtIconIndicator.setLayoutParams(new LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT));
tabView.addView(txtIconIndicator);
View viewIconSelection = new View(getContext());
LinearLayout.LayoutParams viewParams = new LinearLayout.LayoutParams(MATCH_PARENT, 6);
viewParams.setMargins(dpToPx(5), 0, dpToPx(5), 0);
viewIconSelection.setLayoutParams(viewParams);
if (index == 0) {
viewIconSelection.setBackgroundColor(Color.RED);
} else {
viewIconSelection.setBackgroundColor(Color.TRANSPARENT);
}
barViews[index] = viewIconSelection; //Store views in array of views
tabView.addView(viewIconSelection);
addView(tabView, new LinearLayout.LayoutParams(0, MATCH_PARENT, 1));
}
private static Drawable scaleDrawable(Drawable drawable, int width, int height) {
int wi = drawable.getIntrinsicWidth();
int hi = drawable.getIntrinsicHeight();
int dimDiff = Math.abs(wi - width) - Math.abs(hi - height);
float scale = (dimDiff > 0) ? width / (float) wi : height /
(float) hi;
Rect bounds = new Rect(0, 0, (int) (scale * wi), (int) (scale * hi));
drawable.setBounds(bounds);
return drawable;
}
private void animateToTab(final int position) {
final View tabView = 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);
}
public void showSpaceGap() {
if (!gapOpen) {
ResizeWidthAnimation anim = new ResizeWidthAnimation(pageIndicatorEmptySpace, barViews[0].getWidth() - dpToPx(20));
anim.setDuration(DEFAULT_ANIM_TIME);
pageIndicatorEmptySpace.startAnimation(anim);
gapOpen = true;
}
}
public void hideSpaceGap() {
if (gapOpen) {
ResizeWidthAnimation anim = new ResizeWidthAnimation(pageIndicatorEmptySpace, 0);
anim.setDuration(DEFAULT_ANIM_TIME);
pageIndicatorEmptySpace.startAnimation(anim);
gapOpen = false;
}
}
public void toogleGapAnimation() {
ResizeWidthAnimation anim;
if (!gapOpen) {
anim = new ResizeWidthAnimation(pageIndicatorEmptySpace, barViews[0].getWidth() - dpToPx(20));
gapOpen = true;
} else {
anim = new ResizeWidthAnimation(pageIndicatorEmptySpace, 0);
gapOpen = false;
}
anim.setDuration(DEFAULT_ANIM_TIME);
pageIndicatorEmptySpace.startAnimation(anim);
}
public boolean isGapOpen() {
return gapOpen;
}
private static class TabLinearView extends LinearLayout {
private int mIndex;
public TabLinearView(Context context) {
super(context, null, R.attr.vpiTabPageIndicatorStyle);
this.setOrientation(VERTICAL);
this.setLayoutParams(new LinearLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT));
}
public void setIndex(int index) {
this.mIndex = index;
}
public int getIndex() {
return mIndex;
}
}
public int pxToDp(int px) {
DisplayMetrics displayMetrics = getContext().getResources().getDisplayMetrics();
int dp = Math.round(px / (displayMetrics.xdpi / DisplayMetrics.DENSITY_DEFAULT));
return dp;
}
public int dpToPx(float dp) {
DisplayMetrics metrics = getContext().getResources().getDisplayMetrics();
float px = dp * (metrics.densityDpi / 160f);
return (int) px;
}
private static class ResizeWidthAnimation extends Animation {
private int mWidth;
private int mStartWidth;
private View mView;
public ResizeWidthAnimation(View view, int width) {
mView = view;
mWidth = width;
mStartWidth = view.getWidth();
}
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
int newWidth = mStartWidth + (int) ((mWidth - mStartWidth) * interpolatedTime);
mView.getLayoutParams().width = newWidth;
mView.requestLayout();
}
@Override
public void initialize(int width, int height, int parentWidth, int parentHeight) {
super.initialize(width, height, parentWidth, parentHeight);
}
@Override
public boolean willChangeBounds() {
return true;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment