使用代码:

/**
* A PageIndicator is responsible to show an visual indicator on the total views
* number and the current visible view.
*/
public interface PageIndicator extends ViewPager.OnPageChangeListener {
/**
* Bind the indicator to a ViewPager.
*
* @param view
*/
void setViewPager(ViewPager view); /**
* Bind the indicator to a ViewPager.
*
* @param view
* @param initialPosition
*/
void setViewPager(ViewPager view, int initialPosition); /**
* <p>Set the current page of both the ViewPager and indicator.</p>
*
* <p>This <strong>must</strong> be used if you need to set the page before
* the views are drawn on screen (e.g., default start page).</p>
*
* @param item
*/
void setCurrentItem(int item); /**
* Set a page change listener which will receive forwarded events.
*
* @param listener
*/
void setOnPageChangeListener(ViewPager.OnPageChangeListener listener); /**
* Notify the indicator that the fragment list has changed.
*/
void notifyDataSetChanged();
}

TitlePageIndicator 具体重写代码:

TitlePageIndicator extends View implements PageIndicator {
/**
* Percentage indicating what percentage of the screen width away from
* center should the underline be fully faded. A value of 0.25 means that
* halfway between the center of the screen and an edge.
*/
private static final float SELECTION_FADE_PERCENTAGE = 0.25f; /**
* Percentage indicating what percentage of the screen width away from
* center should the selected text bold turn off. A value of 0.05 means
* that 10% between the center and an edge.
*/
private static final float BOLD_FADE_PERCENTAGE = 0.05f; /**
* Title text used when no title is provided by the adapter.
*/
private static final String EMPTY_TITLE = ""; /**
* Interface for a callback when the center item has been clicked.
*/
public interface OnCenterItemClickListener {
/**
* Callback when the center item has been clicked.
*
* @param position Position of the current center item.
*/
void onCenterItemClick(int position);
} public enum IndicatorStyle {
None(0), Triangle(1), Underline(2); public final int value; private IndicatorStyle(int value) {
this.value = value;
} public static IndicatorStyle fromValue(int value) {
for (IndicatorStyle style : IndicatorStyle.values()) {
if (style.value == value) {
return style;
}
}
return null;
}
} public enum LinePosition {
Bottom(0), Top(1); public final int value; private LinePosition(int value) {
this.value = value;
} public static LinePosition fromValue(int value) {
for (LinePosition position : LinePosition.values()) {
if (position.value == value) {
return position;
}
}
return null;
}
} private ViewPager mViewPager;
private ViewPager.OnPageChangeListener mListener;
private int mCurrentPage = -1;
private float mPageOffset;
private int mScrollState;
private final Paint mPaintText = new Paint();
private boolean mBoldText;
private int mColorText;
private int mColorSelected;
private Path mPath = new Path();
private final Rect mBounds = new Rect();
private final Paint mPaintFooterLine = new Paint();
private IndicatorStyle mFooterIndicatorStyle;
private LinePosition mLinePosition;
private final Paint mPaintFooterIndicator = new Paint();
private float mFooterIndicatorHeight;
private float mFooterIndicatorUnderlinePadding;
private float mFooterPadding;
private float mTitlePadding;
private float mTopPadding;
/** Left and right side padding for not active view titles. */
private float mClipPadding;
private float mFooterLineHeight; private static final int INVALID_POINTER = -1; private int mTouchSlop;
private float mLastMotionX = -1;
private int mActivePointerId = INVALID_POINTER;
private boolean mIsDragging; //�Լ�д�� �������Ҿ���
private int TextMaginLeftAndRight=50; private OnCenterItemClickListener mCenterItemClickListener; public TitlePageIndicator(Context context) {
this(context, null);
} public TitlePageIndicator(Context context, AttributeSet attrs) {
this(context, attrs, R.attr.vpiTitlePageIndicatorStyle);
} public TitlePageIndicator(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
if (isInEditMode()) return; //Load defaults from resources
final Resources res = getResources();
final int defaultFooterColor = res.getColor(R.color.default_title_indicator_footer_color);
final float defaultFooterLineHeight = res.getDimension(R.dimen.default_title_indicator_footer_line_height);
final int defaultFooterIndicatorStyle = res.getInteger(R.integer.default_title_indicator_footer_indicator_style);
final float defaultFooterIndicatorHeight = res.getDimension(R.dimen.default_title_indicator_footer_indicator_height);
final float defaultFooterIndicatorUnderlinePadding = res.getDimension(R.dimen.default_title_indicator_footer_indicator_underline_padding);
final float defaultFooterPadding = res.getDimension(R.dimen.default_title_indicator_footer_padding);
final int defaultLinePosition = res.getInteger(R.integer.default_title_indicator_line_position);
final int defaultSelectedColor = res.getColor(R.color.default_title_indicator_selected_color);
final boolean defaultSelectedBold = res.getBoolean(R.bool.default_title_indicator_selected_bold);
final int defaultTextColor = res.getColor(R.color.default_title_indicator_text_color);
final float defaultTextSize = res.getDimension(R.dimen.default_title_indicator_text_size);
final float defaultTitlePadding = res.getDimension(R.dimen.default_title_indicator_title_padding);
final float defaultClipPadding = res.getDimension(R.dimen.default_title_indicator_clip_padding);
final float defaultTopPadding = res.getDimension(R.dimen.default_title_indicator_top_padding); //Retrieve styles attributes
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TitlePageIndicator, defStyle, 0); //Retrieve the colors to be used for this view and apply them.
mFooterLineHeight = a.getDimension(R.styleable.TitlePageIndicator_footerLineHeight, defaultFooterLineHeight);
mFooterIndicatorStyle = IndicatorStyle.fromValue(a.getInteger(R.styleable.TitlePageIndicator_footerIndicatorStyle, defaultFooterIndicatorStyle));
mFooterIndicatorHeight = a.getDimension(R.styleable.TitlePageIndicator_footerIndicatorHeight, defaultFooterIndicatorHeight);
mFooterIndicatorUnderlinePadding = a.getDimension(R.styleable.TitlePageIndicator_footerIndicatorUnderlinePadding, defaultFooterIndicatorUnderlinePadding);
mFooterPadding = a.getDimension(R.styleable.TitlePageIndicator_footerPadding, defaultFooterPadding);
mLinePosition = LinePosition.fromValue(a.getInteger(R.styleable.TitlePageIndicator_linePosition, defaultLinePosition));
mTopPadding = a.getDimension(R.styleable.TitlePageIndicator_topPadding, defaultTopPadding);
mTitlePadding = a.getDimension(R.styleable.TitlePageIndicator_titlePadding, defaultTitlePadding);
mClipPadding = a.getDimension(R.styleable.TitlePageIndicator_clipPadding, defaultClipPadding);
mColorSelected = a.getColor(R.styleable.TitlePageIndicator_selectedColor, defaultSelectedColor);
mColorText = a.getColor(R.styleable.TitlePageIndicator_android_textColor, defaultTextColor);
mBoldText = a.getBoolean(R.styleable.TitlePageIndicator_selectedBold, defaultSelectedBold); final float textSize = a.getDimension(R.styleable.TitlePageIndicator_android_textSize, defaultTextSize);
final int footerColor = a.getColor(R.styleable.TitlePageIndicator_footerColor, defaultFooterColor);
mPaintText.setTextSize(textSize);
mPaintText.setAntiAlias(true);
mPaintFooterLine.setStyle(Paint.Style.FILL_AND_STROKE);
mPaintFooterLine.setStrokeWidth(mFooterLineHeight);
mPaintFooterLine.setColor(footerColor);
mPaintFooterIndicator.setStyle(Paint.Style.FILL_AND_STROKE);
mPaintFooterIndicator.setColor(footerColor); Drawable background = a.getDrawable(R.styleable.TitlePageIndicator_android_background);
if (background != null) {
setBackgroundDrawable(background);
} a.recycle(); final ViewConfiguration configuration = ViewConfiguration.get(context);
mTouchSlop = ViewConfigurationCompat.getScaledPagingTouchSlop(configuration);
} public int getFooterColor() {
return mPaintFooterLine.getColor();
} public void setFooterColor(int footerColor) {
mPaintFooterLine.setColor(footerColor);
mPaintFooterIndicator.setColor(footerColor);
invalidate();
} public float getFooterLineHeight() {
return mFooterLineHeight;
} public void setFooterLineHeight(float footerLineHeight) {
mFooterLineHeight = footerLineHeight;
mPaintFooterLine.setStrokeWidth(mFooterLineHeight);
invalidate();
} public float getFooterIndicatorHeight() {
return mFooterIndicatorHeight;
} public void setFooterIndicatorHeight(float footerTriangleHeight) {
mFooterIndicatorHeight = footerTriangleHeight;
invalidate();
} public float getFooterIndicatorPadding() {
return mFooterPadding;
} public void setFooterIndicatorPadding(float footerIndicatorPadding) {
mFooterPadding = footerIndicatorPadding;
invalidate();
} public IndicatorStyle getFooterIndicatorStyle() {
return mFooterIndicatorStyle;
} public void setFooterIndicatorStyle(IndicatorStyle indicatorStyle) {
mFooterIndicatorStyle = indicatorStyle;
invalidate();
} public LinePosition getLinePosition() {
return mLinePosition;
} public void setLinePosition(LinePosition linePosition) {
mLinePosition = linePosition;
invalidate();
} public int getSelectedColor() {
return mColorSelected;
} public void setSelectedColor(int selectedColor) {
mColorSelected = selectedColor;
invalidate();
} public boolean isSelectedBold() {
return mBoldText;
} public void setSelectedBold(boolean selectedBold) {
mBoldText = selectedBold;
invalidate();
} public int getTextColor() {
return mColorText;
} public void setTextColor(int textColor) {
mPaintText.setColor(textColor);
mColorText = textColor;
invalidate();
} public float getTextSize() {
return mPaintText.getTextSize();
} public void setTextSize(float textSize) {
mPaintText.setTextSize(textSize);
invalidate();
} public float getTitlePadding() {
return this.mTitlePadding;
} public void setTitlePadding(float titlePadding) {
mTitlePadding = titlePadding;
invalidate();
} public float getTopPadding() {
return this.mTopPadding;
} public void setTopPadding(float topPadding) {
mTopPadding = topPadding;
invalidate();
} public float getClipPadding() {
return this.mClipPadding;
} public void setClipPadding(float clipPadding) {
mClipPadding = clipPadding;
invalidate();
} public void setTypeface(Typeface typeface) {
mPaintText.setTypeface(typeface);
invalidate();
} public Typeface getTypeface() {
return mPaintText.getTypeface();
} /*
* (non-Javadoc)
*
* @see android.view.View#onDraw(android.graphics.Canvas)
*/
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas); if (mViewPager == null) {
return;
}
final int count = mViewPager.getAdapter().getCount();
if (count == 0) {
return;
} // mCurrentPage is -1 on first start and after orientation changed. If so, retrieve the correct index from viewpager.
if (mCurrentPage == -1 && mViewPager != null) {
mCurrentPage = mViewPager.getCurrentItem();
} //Calculate views bounds
ArrayList<Rect> bounds = calculateAllBounds(mPaintText);
final int boundsSize = bounds.size(); //Make sure we're on a page that still exists
if (mCurrentPage >= boundsSize) {
setCurrentItem(boundsSize - 1);
return;
} final int countMinusOne = count - 1;
final float halfWidth = getWidth() / 2f;
final int left = getLeft();
final float leftClip = left + mClipPadding;
final int width = getWidth();
int height = getHeight();
final int right = left + width;
final float rightClip = right - mClipPadding; int page = mCurrentPage;
float offsetPercent;
if (mPageOffset <= 0.5) {
offsetPercent = mPageOffset;
} else {
page += 1;
offsetPercent = 1 - mPageOffset;
}
final boolean currentSelected = (offsetPercent <= SELECTION_FADE_PERCENTAGE);
final boolean currentBold = (offsetPercent <= BOLD_FADE_PERCENTAGE);
final float selectedPercent = (SELECTION_FADE_PERCENTAGE - offsetPercent) / SELECTION_FADE_PERCENTAGE; //Verify if the current view must be clipped to the screen
Rect curPageBound = bounds.get(mCurrentPage);
float curPageWidth = curPageBound.right - curPageBound.left;
if (curPageBound.left < leftClip) {
//Try to clip to the screen (left side)
clipViewOnTheLeft(curPageBound, curPageWidth, left);
}
if (curPageBound.right > rightClip) {
//Try to clip to the screen (right side)
clipViewOnTheRight(curPageBound, curPageWidth, right);
} //Left views starting from the current position
if (mCurrentPage > 0) {
for (int i = mCurrentPage - 1; i >= 0; i--) {
Rect bound = bounds.get(i);
//Is left side is outside the screen
if (bound.left < leftClip) {
int w = bound.right - bound.left;
//Try to clip to the screen (left side)
clipViewOnTheLeft(bound, w, left);
//Except if there's an intersection with the right view
Rect rightBound = bounds.get(i + 1);
//Intersection
if (bound.right + mTitlePadding > rightBound.left) {
bound.left = (int) (rightBound.left - w - mTitlePadding);
bound.right = bound.left + w;
}
}
}
}
//Right views starting from the current position
if (mCurrentPage < countMinusOne) {
for (int i = mCurrentPage + 1 ; i < count; i++) {
Rect bound = bounds.get(i);
//If right side is outside the screen
if (bound.right > rightClip) {
int w = bound.right - bound.left;
//Try to clip to the screen (right side)
clipViewOnTheRight(bound, w, right);
//Except if there's an intersection with the left view
Rect leftBound = bounds.get(i - 1);
//Intersection
if (bound.left - mTitlePadding < leftBound.right) {
bound.left = (int) (leftBound.right + mTitlePadding);
bound.right = bound.left + w;
}
}
}
} //Now draw views
int colorTextAlpha = mColorText >>> 24;
for (int i = 0; i < count; i++) {
//Get the title
Rect bound = bounds.get(i);
//Only if one side is visible
if ((bound.left > left && bound.left < right) || (bound.right > left && bound.right < right)) {
final boolean currentPage = (i == page);
final CharSequence pageTitle = getTitle(i); //Only set bold if we are within bounds
mPaintText.setFakeBoldText(currentPage && currentBold && mBoldText); //Draw text as unselected
mPaintText.setColor(mColorText);
if(currentPage && currentSelected) {
//Fade out/in unselected text as the selected text fades in/out
mPaintText.setAlpha(colorTextAlpha - (int)(colorTextAlpha * selectedPercent));
} //Except if there's an intersection with the right view
if (i < boundsSize - 1) {
Rect rightBound = bounds.get(i + 1);
//Intersection
if (bound.right + mTitlePadding > rightBound.left) {
int w = bound.right - bound.left;
bound.left = (int) (rightBound.left - w - mTitlePadding);
bound.right = bound.left + w;
}
}
canvas.drawText(pageTitle, 0, pageTitle.length(), bound.left+TextMaginLeftAndRight/2, bound.bottom + mTopPadding, mPaintText); //If we are within the selected bounds draw the selected text
if (currentPage && currentSelected) {
mPaintText.setColor(mColorSelected);
mPaintText.setAlpha((int)((mColorSelected >>> 24) * selectedPercent));
canvas.drawText(pageTitle, 0, pageTitle.length(), bound.left+TextMaginLeftAndRight/2, bound.bottom + mTopPadding, mPaintText);
}
}
} //If we want the line on the top change height to zero and invert the line height to trick the drawing code
float footerLineHeight = mFooterLineHeight;
float footerIndicatorLineHeight = mFooterIndicatorHeight;
if (mLinePosition == LinePosition.Top) {
height = 0;
footerLineHeight = -footerLineHeight;
footerIndicatorLineHeight = -footerIndicatorLineHeight;
} //Draw the footer line
mPath.reset();
mPath.moveTo(0, height - footerLineHeight / 2f);
mPath.lineTo(width, height - footerLineHeight / 2f);
mPath.close();
canvas.drawPath(mPath, mPaintFooterLine); float heightMinusLine = height - footerLineHeight;
switch (mFooterIndicatorStyle) {
case Triangle:
mPath.reset();
mPath.moveTo(halfWidth, heightMinusLine - footerIndicatorLineHeight);
mPath.lineTo(halfWidth + footerIndicatorLineHeight, heightMinusLine);
mPath.lineTo(halfWidth - footerIndicatorLineHeight, heightMinusLine);
mPath.close();
canvas.drawPath(mPath, mPaintFooterIndicator);
break; case Underline:
if (!currentSelected || page >= boundsSize) {
break;
} Rect underlineBounds = bounds.get(page);
final float rightPlusPadding = underlineBounds.right + mFooterIndicatorUnderlinePadding;
final float leftMinusPadding = underlineBounds.left - mFooterIndicatorUnderlinePadding;
final float heightMinusLineMinusIndicator = heightMinusLine - footerIndicatorLineHeight; mPath.reset();
mPath.moveTo(leftMinusPadding, heightMinusLine);
mPath.lineTo(rightPlusPadding, heightMinusLine);
mPath.lineTo(rightPlusPadding, heightMinusLineMinusIndicator);
mPath.lineTo(leftMinusPadding, heightMinusLineMinusIndicator);
mPath.close(); mPaintFooterIndicator.setAlpha((int)(0xFF * selectedPercent));
canvas.drawPath(mPath, mPaintFooterIndicator);
mPaintFooterIndicator.setAlpha(0xFF);
break;
}
} public boolean onTouchEvent(android.view.MotionEvent ev) {
if (super.onTouchEvent(ev)) {
return true;
}
if ((mViewPager == null) || (mViewPager.getAdapter().getCount() == 0)) {
return false;
} final int action = ev.getAction() & MotionEventCompat.ACTION_MASK;
switch (action) {
case MotionEvent.ACTION_DOWN:
mActivePointerId = MotionEventCompat.getPointerId(ev, 0);
mLastMotionX = ev.getX();
break; case MotionEvent.ACTION_MOVE: {
final int activePointerIndex = MotionEventCompat.findPointerIndex(ev, mActivePointerId);
final float x = MotionEventCompat.getX(ev, activePointerIndex);
final float deltaX = x - mLastMotionX; if (!mIsDragging) {
if (Math.abs(deltaX) > mTouchSlop) {
mIsDragging = true;
}
} if (mIsDragging) {
mLastMotionX = x;
if (mViewPager.isFakeDragging() || mViewPager.beginFakeDrag()) {
mViewPager.fakeDragBy(deltaX);
}
} break;
} case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
if (!mIsDragging) {
final int count = mViewPager.getAdapter().getCount();
final int width = getWidth();
final float halfWidth = width / 2f;
final float sixthWidth = width / 6f;
final float leftThird = halfWidth - sixthWidth;
final float rightThird = halfWidth + sixthWidth;
final float eventX = ev.getX(); if (eventX < leftThird) {
if (mCurrentPage > 0) {
if (action != MotionEvent.ACTION_CANCEL) {
mViewPager.setCurrentItem(mCurrentPage - 1);
}
return true;
}
} else if (eventX > rightThird) {
if (mCurrentPage < count - 1) {
if (action != MotionEvent.ACTION_CANCEL) {
mViewPager.setCurrentItem(mCurrentPage + 1);
}
return true;
}
} else {
//Middle third
if (mCenterItemClickListener != null && action != MotionEvent.ACTION_CANCEL) {
mCenterItemClickListener.onCenterItemClick(mCurrentPage);
}
}
} mIsDragging = false;
mActivePointerId = INVALID_POINTER;
if (mViewPager.isFakeDragging()) mViewPager.endFakeDrag();
break; case MotionEventCompat.ACTION_POINTER_DOWN: {
final int index = MotionEventCompat.getActionIndex(ev);
mLastMotionX = MotionEventCompat.getX(ev, index);
mActivePointerId = MotionEventCompat.getPointerId(ev, index);
break;
} case MotionEventCompat.ACTION_POINTER_UP:
final int pointerIndex = MotionEventCompat.getActionIndex(ev);
final int pointerId = MotionEventCompat.getPointerId(ev, pointerIndex);
if (pointerId == mActivePointerId) {
final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
mActivePointerId = MotionEventCompat.getPointerId(ev, newPointerIndex);
}
mLastMotionX = MotionEventCompat.getX(ev, MotionEventCompat.findPointerIndex(ev, mActivePointerId));
break;
} return true;
} /**
* Set bounds for the right textView including clip padding.
*
* @param curViewBound
* current bounds.
* @param curViewWidth
* width of the view.
*/
private void clipViewOnTheRight(Rect curViewBound, float curViewWidth, int right) {
curViewBound.right = (int) (right - mClipPadding);
curViewBound.left = (int) (curViewBound.right - curViewWidth);
} /**
* Set bounds for the left textView including clip padding.
*
* @param curViewBound
* current bounds.
* @param curViewWidth
* width of the view.
*/
private void clipViewOnTheLeft(Rect curViewBound, float curViewWidth, int left) {
curViewBound.left = (int) (left + mClipPadding);
curViewBound.right = (int) (mClipPadding + curViewWidth);
} /**
* Calculate views bounds and scroll them according to the current index
*
* @param paint
* @return
*/
private ArrayList<Rect> calculateAllBounds(Paint paint) {
ArrayList<Rect> list = new ArrayList<Rect>();
//For each views (If no values then add a fake one)
final int count = mViewPager.getAdapter().getCount();
final int width = getWidth();
final int halfWidth = width / 2;
for (int i = 0; i < count; i++) {
Rect bounds = calcBounds(i, paint);
int w = bounds.right - bounds.left;
int h = bounds.bottom - bounds.top;
bounds.left = (int)(halfWidth - (w / 2f) + ((i - mCurrentPage - mPageOffset) * width));
bounds.right = bounds.left + w;
bounds.top = 0;
bounds.bottom = h;
list.add(bounds);
} return list;
} /**
* Calculate the bounds for a view's title
*
* @param index
* @param paint
* @return
*/
private Rect calcBounds(int index, Paint paint) {
//Calculate the text bounds
Rect bounds = new Rect();
CharSequence title = getTitle(index);
bounds.right = (int) paint.measureText(title, 0, title.length())+TextMaginLeftAndRight;
bounds.bottom = (int) (paint.descent() - paint.ascent());
return bounds;
} @Override
public void setViewPager(ViewPager view) {
if (mViewPager == view) {
return;
}
if (mViewPager != null) {
mViewPager.setOnPageChangeListener(null);
}
if (view.getAdapter() == null) {
throw new IllegalStateException("ViewPager does not have adapter instance.");
}
mViewPager = view;
mViewPager.setOnPageChangeListener(this);
invalidate();
} @Override
public void setViewPager(ViewPager view, int initialPosition) {
setViewPager(view);
setCurrentItem(initialPosition);
} @Override
public void notifyDataSetChanged() {
invalidate();
} /**
* Set a callback listener for the center item click.
*
* @param listener Callback instance.
*/
public void setOnCenterItemClickListener(OnCenterItemClickListener listener) {
mCenterItemClickListener = listener;
} @Override
public void setCurrentItem(int item) {
if (mViewPager == null) {
throw new IllegalStateException("ViewPager has not been bound.");
}
mViewPager.setCurrentItem(item);
mCurrentPage = item;
invalidate();
} @Override
public void onPageScrollStateChanged(int state) {
mScrollState = state; if (mListener != null) {
mListener.onPageScrollStateChanged(state);
}
} @Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
mCurrentPage = position;
mPageOffset = positionOffset;
invalidate(); if (mListener != null) {
mListener.onPageScrolled(position, positionOffset, positionOffsetPixels);
}
} @Override
public void onPageSelected(int position) {
if (mScrollState == ViewPager.SCROLL_STATE_IDLE) {
mCurrentPage = position;
invalidate();
} if (mListener != null) {
mListener.onPageSelected(position);
}
} @Override
public void setOnPageChangeListener(ViewPager.OnPageChangeListener listener) {
mListener = listener;
} @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//Measure our width in whatever mode specified
final int measuredWidth = MeasureSpec.getSize(widthMeasureSpec); //Determine our height
float height;
final int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
if (heightSpecMode == MeasureSpec.EXACTLY) {
//We were told how big to be
height = MeasureSpec.getSize(heightMeasureSpec);
} else {
//Calculate the text bounds
mBounds.setEmpty();
mBounds.bottom = (int) (mPaintText.descent() - mPaintText.ascent());
height = mBounds.bottom - mBounds.top + mFooterLineHeight + mFooterPadding + mTopPadding;
if (mFooterIndicatorStyle != IndicatorStyle.None) {
height += mFooterIndicatorHeight;
}
}
final int measuredHeight = (int)height; setMeasuredDimension(measuredWidth, measuredHeight);
} @Override
public void onRestoreInstanceState(Parcelable state) {
SavedState savedState = (SavedState)state;
super.onRestoreInstanceState(savedState.getSuperState());
mCurrentPage = savedState.currentPage;
requestLayout();
} @Override
public Parcelable onSaveInstanceState() {
Parcelable superState = super.onSaveInstanceState();
SavedState savedState = new SavedState(superState);
savedState.currentPage = mCurrentPage;
return savedState;
} static class SavedState extends BaseSavedState {
int currentPage; public SavedState(Parcelable superState) {
super(superState);
} private SavedState(Parcel in) {
super(in);
currentPage = in.readInt();
} @Override
public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags);
dest.writeInt(currentPage);
} @SuppressWarnings("UnusedDeclaration")
public static final Parcelable.Creator<SavedState> CREATOR = new Parcelable.Creator<SavedState>() {
@Override
public SavedState createFromParcel(Parcel in) {
return new SavedState(in);
} @Override
public SavedState[] newArray(int size) {
return new SavedState[size];
}
};
} private CharSequence getTitle(int i) {
CharSequence title = mViewPager.getAdapter().getPageTitle(i);
if (title == null) {
title = EMPTY_TITLE;
}
return title;
}
}

github上面有个开源的也实现勒这个效果:
https://github.com/JakeWharton/Android-ViewPagerIndicator

Android之把eoe客户端的关联ViewPager的滑动条勾出来使用的更多相关文章

  1. Android中ViewPager实现滑动条及与Fragment结合的实例教程

    ViewPager类主要被用来实现可滑动的视图功能,这里我们就来共同学习Android中ViewPager实现滑动条及与Fragment结合的实例教程,需要的朋友可以参考下 自主实现滑动指示条先上一个 ...

  2. 介绍三个Android支持库控件:TabLayout+ViewPager+RecyclerView

    本文主要介绍如下三个Android支持库控件的配合使用: TabLayout:android.support.design.widget.TabLayout ViewPager:android.sup ...

  3. Android中如何在Eclipse中关联源代码?(图文)

    关联源代码 1.删除工程里面的Android Depandencies,删除后会报错,不要理会.看下面 2.添加libs目录下的Android-support-v4.jar包 选中-->右键-- ...

  4. Android之自定义(上方标题随ViewPager手势慢慢滑动)

    最近很蛋疼,项目要模仿网易新闻的样式去做.上次把仿网易新闻客户端的下拉刷新写出来了,这次是ViewPager的滑动,同时ViewPager的上面标题下划线跟随者移动,本来通过ViewPager的OnP ...

  5. Android Studio2.x版本无法自动关联源码的解决方法

    Android Studio2.x版本无法自动关联源码的解决方法 在学习android开发过程中,对于一个不熟悉的类,阅读源码是一个很好的学习方式,使用andorid studio开发工具的SDK M ...

  6. Android版的菜谱客户端应用源码完整版

    Android版的菜谱客户端应用源码完整版,这个文章是从安卓教程网转载过来的,不是本人的原创,希望能够帮到大家的学习吧. <ignore_js_op> 152936qc7jdnv6vo0c ...

  7. Android 禁止Viewpager左右滑动功能

    首先自定义一个 继承自 ViewPager的自定义 类 package com.yourcompany; import android.content.Context; import android. ...

  8. Android手机SSH Client客户端推荐JuiceSSH

    Windows上建立ssh服务器 参见: http://www.cnblogs.com/xred/archive/2012/04/21/2461627.html Android手机SSH Client ...

  9. Android Studio撤销与SVN的关联

    为何会记录这一个问题,主要是在做项目的过程中出现了一个奇怪的现象,就是直接在文件目录下使用svn上传文件的话,可以看到该目录是与SVN相关联的,可是到了用Android Studio上传代码的时候却发 ...

随机推荐

  1. Servlet发送Http请求

    今日遇到一个需求,android注册,短信验证码功能. android请求我服务端,我请求tosms.cn发送验证码短信给android,于是需要在Servlet中发送Http请求 package o ...

  2. Java登陆拦截器

    package com.beidou.warehouseerp.interceptor; import com.alibaba.fastjson.JSON; import com.beidou.war ...

  3. Oracle JDK vs OpenJDK

    OpenJDK是Sun在2006年末把Java开源而形成的项目,这里的“开源”是通常意义上的源码开放形式,即源码是可被复用的,例如IcedTea.UltraViolet都是从OpenJDK源码衍生出的 ...

  4. 一步一步学习IdentityServer3 (2)

    下面就来做一个例子:IdentityServer3服务端的配置 VS2015创建一个MVC项目 IdrOAuth 用来授权的认证的站点

  5. 【LOJ】#2178. 「BJOI2017」机动训练

    题解 遇见平方和就转有序对呗 dp类似从很多点出发每次走一步的转移方式 然后我too naive的,枚举路径长度来决定更新次数,愉快TLE 改成记搜就过了 代码 #include <bits/s ...

  6. Caffe训练AlexNet网络模型——问题三

    caffe 进行自己的imageNet训练分类:loss一直是87.3365,accuracy一直是0 解决方法: http://blog.csdn.net/jkfdqjjy/article/deta ...

  7. select 详解

    In summary, a socket will be identified in a particular set when select returns if: readfds:If liste ...

  8. P1164 小A点菜 洛谷

    题目背景 uim神犇拿到了uoi的ra(镭牌)后,立刻拉着基友小A到了一家……餐馆,很低端的那种. uim指着墙上的价目表(太低级了没有菜单),说:“随便点”. 题目描述 不过uim由于买了一些辅(e ...

  9. 【noip模拟赛1】古韵之乞巧 (dp)

    描述 闺女求天女,更阑意未阑. 玉庭开粉席,罗袖捧金盘. 向月穿针易,临风整线难. 不知谁得巧,明旦试相看. ——祖咏<七夕> 女子乞巧,是七夕的重头戏.古时,女子擅长女红被视为一种重要的 ...

  10. Ubuntu 18.04 下配置 HAXM 加速 Android模拟器

    Ubuntu 18.04 下配置 HAXM 加速 Android模拟器 最近在vmware环境下搭建ubuntu18.04开发环境,开始发现总是运行android模拟器在console提示加载如下错误 ...