Last active
August 23, 2016 08:55
-
-
Save mio4kon/c2b24cb3eb18a2a8a76c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.nonobank.ui.widget; | |
import android.content.Context; | |
import android.graphics.Canvas; | |
import android.graphics.Paint; | |
import android.graphics.Typeface; | |
import android.support.v4.view.ViewCompat; | |
import android.support.v4.view.ViewPager; | |
import android.support.v4.view.ViewPager.OnPageChangeListener; | |
import android.support.v4.widget.EdgeEffectCompat; | |
import android.support.v4.widget.ScrollerCompat; | |
import android.util.AttributeSet; | |
import android.util.TypedValue; | |
import android.view.Gravity; | |
import android.view.MotionEvent; | |
import android.view.VelocityTracker; | |
import android.view.View; | |
import android.view.ViewConfiguration; | |
import android.view.ViewGroup; | |
import android.view.ViewParent; | |
import android.view.ViewTreeObserver; | |
import android.widget.ImageButton; | |
import android.widget.TextView; | |
import com.nonobank.R; | |
import com.nonobank.common.utils.LogUtils; | |
import com.nonobank.ui.activity.BaseActivity; | |
import com.nonobank.utils.UIUtils; | |
/** | |
* <p>Created by mio on 14-12-26. </p> | |
* **如果要实现ViewPager的OnPageChangeListener请使用PagerTab的OnPageChangeListener** | |
*/ | |
public class PagerTab extends ViewGroup { | |
private ViewPager mViewPager; | |
private PageListener mPageListener = new PageListener ();//用于注册给ViewPager监听状态和滚动 | |
/** | |
* 外界设置的OnPageChangeListener(委托)--PageTab设置的 | |
*/ | |
private OnPageChangeListener mDelegatePageListener; | |
/** | |
* 分割线上下的padding | |
*/ | |
private int mDividerPadding = 12; | |
private int mDividerWidth = 1; | |
private int mDividerColor = 0x1A000000;//分割线颜色 | |
private Paint mDividerPaint;//分割线的画笔 | |
/** | |
* 指示器的高度 | |
*/ | |
private int mIndicatorHeight = 4; | |
private int mIndicatorWidth;//指示器的宽度,是动态的随着tab的宽度变化 | |
private int mIndicatorLeft;//指示器的距离左边的距离 | |
private int mIndicatorColor = 0xff96b63c;//指示器颜色 | |
private Paint mIndicatorPaint; //指示器的画笔 | |
private int mContentWidth;//记录自身内容的宽度 | |
private int mContentHeight;//记录自身内容的高度 | |
/** | |
* tab左右的内边距 | |
*/ | |
private int mTabPadding = 24; | |
private int mTabTextSize = 16; //tab文字大小 | |
private int mTabBackgroundResId = R.drawable.bg_tab_text;// tab背景资源 | |
private int mTabTextColorResId = R.color.tab_text_color; //tab文字颜色 | |
private int mTabCount;//tab的个数 | |
private int mCurrentPosition = 0;//当前光标所处的tab,规则是以光标的最左端所在的item的position | |
private float mCurrentOffsetPixels;//光标左边距离当前光标所处的tab的左边距离 | |
private int mSelectedPosition = 0; //当前被选中的tab,用于记录手指点击tab的position | |
private boolean mIsBeingDragged = false;//是否处于拖动中 | |
private float mLastMotionX;//上一次手指触摸的x坐标 | |
private VelocityTracker mVelocityTracker;//用于记录速度的帮助类 | |
private int mMinimumVelocity;//系统默认的最小满足fling的速度 | |
private int mMaximumVelocity;//系统默认最大的fling速度 | |
private int mTouchSlop;//系统默认满足滑动的最小位移 | |
/** | |
* 处理滚动的帮助者 | |
*/ | |
private ScrollerCompat mScroller; | |
private int mLastScrollX;//记录上一次滚动的x位置,这是用于处理overScroll,实际位置可能会受到限制 | |
private int mMaxScrollX = 0;// 控件最大可滚动的距离 | |
private int mSplitScrollX = 0;// 根据item的个数,计算出每移动一个item控件需要移动的距离 | |
/** | |
* 处理overScroll的反馈效果,类似ViewPager滑到头有效果 | |
*/ | |
private EdgeEffectCompat mLeftEdge; | |
private EdgeEffectCompat mRightEdge; | |
private int defalutPosition = 0; | |
public PagerTab(Context context) { | |
this (context, null); | |
} | |
public PagerTab(Context context, AttributeSet attrs) { | |
this (context, attrs, 0); | |
} | |
public PagerTab(Context context, AttributeSet attrs, int defStyle) { | |
super (context, attrs, defStyle); | |
init (); | |
initPaint (); | |
} | |
/** | |
* 初始化一些常量 | |
*/ | |
private void init() { | |
//把一个值从dip转换成px | |
mIndicatorHeight = UIUtils.dip2px (mIndicatorHeight); | |
mDividerPadding = UIUtils.dip2px (mDividerPadding); | |
mTabPadding = UIUtils.dip2px (mTabPadding); | |
mDividerWidth = UIUtils.dip2px (mDividerWidth); | |
mTabTextSize = UIUtils.dip2px (mTabTextSize); | |
//创建一个scroller | |
mScroller = ScrollerCompat.create (getContext ()); | |
//获取一个系统关于View的常量配置类 | |
final ViewConfiguration configuration = ViewConfiguration.get (getContext ()); | |
//获取滑动的最小距离 | |
mTouchSlop = configuration.getScaledTouchSlop (); | |
//获取fling的最小速度 | |
mMinimumVelocity = configuration.getScaledMinimumFlingVelocity (); | |
//获取fling的最大速度 | |
mMaximumVelocity = configuration.getScaledMaximumFlingVelocity (); | |
mLeftEdge = new EdgeEffectCompat (getContext ()); | |
mRightEdge = new EdgeEffectCompat (getContext ()); | |
} | |
/** | |
* 初始画笔 | |
*/ | |
private void initPaint() { | |
mIndicatorPaint = new Paint (); | |
mIndicatorPaint.setAntiAlias (true); | |
mIndicatorPaint.setStyle (Paint.Style.FILL); | |
mIndicatorPaint.setColor (mIndicatorColor); | |
mDividerPaint = new Paint (); | |
mDividerPaint.setAntiAlias (true); | |
mDividerPaint.setStrokeWidth (mDividerWidth); | |
mDividerPaint.setColor (mDividerColor); | |
} | |
/** | |
* 设置ViewPager | |
*/ | |
public void setViewPager(ViewPager viewPager) { | |
if (viewPager == null || viewPager.getAdapter () == null) { | |
throw new IllegalStateException ("ViewPager is null or ViewPager does not have adapter instance."); | |
} | |
mViewPager = viewPager; | |
onViewPagerChanged (); | |
} | |
private void onViewPagerChanged() { | |
mViewPager.setOnPageChangeListener (mPageListener);//给ViewPager设置监听 | |
mTabCount = mViewPager.getAdapter ().getCount ();//有多少个tab需要看ViewPager有多少个页面 | |
for(int i = 0; i < mTabCount; i++) { | |
if (mViewPager.getAdapter () instanceof IconTabProvider) {//如果想要使用icon作为tab,则需要adapter实现IconTabProvider接口 | |
addIconTab (i, ((IconTabProvider) mViewPager.getAdapter ()).getPageIconResId (i)); | |
} else { | |
addTextTab (i, mViewPager.getAdapter ().getPageTitle (i).toString ()); | |
} | |
} | |
ViewTreeObserver viewTreeObserver = getViewTreeObserver (); | |
if (viewTreeObserver != null) {//监听第一个的全局layout事件,来设置当前的mCurrentPosition,显示对应的tab | |
viewTreeObserver.addOnGlobalLayoutListener (new ViewTreeObserver.OnGlobalLayoutListener () { | |
@Override | |
public void onGlobalLayout() { | |
getViewTreeObserver ().removeGlobalOnLayoutListener (this);//只需要监听一次,之后通过listener回调即可 | |
mCurrentPosition = mViewPager.getCurrentItem (); | |
if (mDelegatePageListener != null) { | |
mDelegatePageListener.onPageSelected (mCurrentPosition); | |
} | |
} | |
}); | |
} | |
} | |
/** | |
* 设置监听,因为Tab会监听ViewPager的状态,所以不要给ViewPager设置监听了,设置给Tab,由Tab转发 | |
*/ | |
public void setOnPageChangeListener(OnPageChangeListener listener) { | |
mDelegatePageListener = listener; | |
} | |
/** | |
* 添加文字tab | |
*/ | |
private void addTextTab(final int position, String title) { | |
TextView tab = new TextView (getContext ()); | |
tab.setText (title); | |
tab.setGravity (Gravity.CENTER); | |
tab.setSingleLine (); | |
tab.setTextSize (TypedValue.COMPLEX_UNIT_PX, mTabTextSize); | |
tab.setTypeface (Typeface.defaultFromStyle (Typeface.BOLD)); | |
tab.setTextColor (UIUtils.getColorStateList (mTabTextColorResId)); | |
tab.setBackgroundDrawable (UIUtils.getDrawable (mTabBackgroundResId)); | |
tab.setLayoutParams (new LayoutParams (LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT)); | |
//默认第1个tab是选中状态 | |
if (position == defalutPosition) { | |
tab.setSelected (true); | |
mViewPager.setCurrentItem (defalutPosition); | |
} | |
addTab (position, tab); | |
} | |
/** | |
* 添加图片icon | |
*/ | |
private void addIconTab(final int position, int resId) { | |
ImageButton tab = new ImageButton (getContext ()); | |
tab.setImageResource (resId); | |
tab.setLayoutParams (new LayoutParams (LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); | |
addTab (position, tab); | |
} | |
/** | |
* 将Tab添加到自身 & 添加点击事件 * | |
*/ | |
private void addTab(final int position, View tab) { | |
tab.setFocusable (true); | |
//设置tab的点击事件,当tab被点击时候切换pager的页面 | |
tab.setOnClickListener (new OnClickListener () { | |
@Override | |
public void onClick(View v) { | |
mViewPager.setCurrentItem (position); | |
} | |
}); | |
tab.setPadding (mTabPadding, 0, mTabPadding, 0); | |
addView (tab, position); | |
} | |
/** | |
* 测量时的回调 | |
*/ | |
@Override | |
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { | |
// 获取控件自身的宽高,模式 | |
int widthSize = MeasureSpec.getSize (widthMeasureSpec) - getPaddingLeft () - getPaddingRight (); | |
int heightSize = MeasureSpec.getSize (heightMeasureSpec) - getPaddingBottom () - getPaddingBottom (); | |
int widthMode = MeasureSpec.getMode (widthMeasureSpec); | |
int heightMode = MeasureSpec.getMode (heightMeasureSpec); | |
int totalWidth = 0; | |
int highest = 0; | |
int goneChildCount = 0; | |
for(int i = 0; i < mTabCount; i++) { | |
final View child = getChildAt (i); | |
if (child == null || child.getVisibility () == View.GONE) { | |
goneChildCount++; | |
continue; | |
} | |
int childWidthMeasureSpec; | |
int childHeightMeasureSpec; | |
LayoutParams childLayoutParams = child.getLayoutParams (); | |
if (childLayoutParams == null) { | |
childLayoutParams = new LayoutParams (LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); | |
} | |
if (childLayoutParams.width == LayoutParams.MATCH_PARENT) { | |
childWidthMeasureSpec = MeasureSpec.makeMeasureSpec (widthSize, MeasureSpec.EXACTLY); | |
} else if (childLayoutParams.width == LayoutParams.WRAP_CONTENT) { | |
childWidthMeasureSpec = MeasureSpec.makeMeasureSpec (widthSize, MeasureSpec.AT_MOST); | |
} else { | |
childWidthMeasureSpec = MeasureSpec.makeMeasureSpec (childLayoutParams.width, MeasureSpec.EXACTLY); | |
} | |
if (childLayoutParams.height == LayoutParams.MATCH_PARENT) { | |
childHeightMeasureSpec = MeasureSpec.makeMeasureSpec (heightSize, MeasureSpec.EXACTLY); | |
} else if (childLayoutParams.height == LayoutParams.WRAP_CONTENT) { | |
childHeightMeasureSpec = MeasureSpec.makeMeasureSpec (heightSize, MeasureSpec.AT_MOST); | |
} else { | |
childHeightMeasureSpec = MeasureSpec.makeMeasureSpec (childLayoutParams.height, MeasureSpec.EXACTLY); | |
} | |
child.measure (childWidthMeasureSpec, childHeightMeasureSpec); | |
int childWidth = child.getMeasuredWidth (); | |
int childHeight = child.getMeasuredHeight (); | |
totalWidth += childWidth; | |
highest = highest < childHeight ? childHeight : highest; | |
} | |
if (totalWidth <= widthSize) {//如果子Tab的总宽度小于PagerTab,则采用平分模式 | |
int splitWidth = (int) (widthSize / (mTabCount - goneChildCount + 0.0f) + 0.5f); | |
for(int i = 0; i < mTabCount; i++) { | |
final View child = getChildAt (i); | |
if (child == null || child.getVisibility () == View.GONE) { | |
continue; | |
} | |
int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec (splitWidth, MeasureSpec.EXACTLY); | |
int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec (child.getMeasuredHeight (), MeasureSpec.EXACTLY); | |
child.measure (childWidthMeasureSpec, childHeightMeasureSpec); | |
} | |
mMaxScrollX = 0; | |
mSplitScrollX = 0; | |
} else {//如果所有子View大于控件的宽度 | |
mMaxScrollX = totalWidth - widthSize; | |
mSplitScrollX = (int) (mMaxScrollX / (mTabCount - goneChildCount - 1.0f) + 0.5f); | |
} | |
if (widthMode == MeasureSpec.EXACTLY) { | |
mContentWidth = widthSize; | |
} else { | |
mContentWidth = totalWidth; | |
} | |
if (heightMode == MeasureSpec.EXACTLY) { | |
mContentHeight = heightSize; | |
} else { | |
mContentHeight = highest; | |
} | |
int measureWidth = mContentWidth + getPaddingLeft () + getPaddingRight (); | |
int measureHeight = mContentHeight + getPaddingTop () + getPaddingBottom (); | |
setMeasuredDimension (measureWidth, measureHeight); | |
} | |
/** | |
* 布局时的回调 | |
*/ | |
@Override | |
protected void onLayout(boolean changed, int l, int t, int r, int b) {//这里简化了,没有考虑margin的情况 | |
if (changed) { | |
int height = b - t;//控件供子View显示的高度 | |
int left = l; | |
for(int i = 0; i < mTabCount; i++) { | |
final View child = getChildAt (i); | |
if (child == null || child.getVisibility () == View.GONE) { | |
continue; | |
} | |
int top = (int) ((height - child.getMeasuredHeight ()) / 2.0f + 0.5f);//如果控件比tab要高,则居中显示 | |
int right = left + child.getMeasuredWidth (); | |
child.layout (left, top, right, top + child.getMeasuredHeight ());//摆放tab | |
left = right;//因为是水平摆放的,所以为下一个准备left值 | |
} | |
} | |
} | |
/** | |
* 绘制时的回调 | |
*/ | |
@Override | |
protected void onDraw(Canvas canvas) { | |
super.onDraw (canvas); | |
final int height = getHeight (); | |
//画指示器 | |
canvas.drawRect (mIndicatorLeft, height - mIndicatorHeight, mIndicatorLeft + mIndicatorWidth, height, mIndicatorPaint); | |
// 画分割线 | |
for(int i = 0; i < mTabCount - 1; i++) {//分割线的个数比tab的个数少一个 | |
final View child = getChildAt (i); | |
if (child == null || child.getVisibility () == View.GONE) { | |
continue; | |
} | |
if (child != null) { | |
canvas.drawLine (child.getRight (), mDividerPadding, child.getRight (), mContentHeight - mDividerPadding, mDividerPaint); | |
} | |
} | |
// 因为overScroll效果是一个持续效果,所以需要持续画--参见ViewPager源码 | |
boolean needsInvalidate = false; | |
if (!mLeftEdge.isFinished ()) {//如果效果没停止 | |
final int restoreCount = canvas.save ();//先保存当前画布 | |
final int heightEdge = getHeight () - getPaddingTop () - getPaddingBottom (); | |
final int widthEdge = getWidth (); | |
canvas.rotate (270); | |
canvas.translate (-heightEdge + getPaddingTop (), 0); | |
mLeftEdge.setSize (heightEdge, widthEdge); | |
needsInvalidate |= mLeftEdge.draw (canvas); | |
canvas.restoreToCount (restoreCount); | |
} | |
if (!mRightEdge.isFinished ()) { | |
final int restoreCount = canvas.save (); | |
final int widthEdge = getWidth (); | |
final int heightEdge = getHeight () - getPaddingTop () - getPaddingBottom (); | |
canvas.rotate (90); | |
canvas.translate (-getPaddingTop (), -(widthEdge + mMaxScrollX)); | |
mRightEdge.setSize (heightEdge, widthEdge); | |
needsInvalidate |= mRightEdge.draw (canvas); | |
canvas.restoreToCount (restoreCount); | |
} | |
if (needsInvalidate) { | |
postInvalidate (); | |
} | |
} | |
/** | |
* 触摸事件是否拦截的方法 | |
*/ | |
@Override | |
public boolean onInterceptTouchEvent(MotionEvent ev) { | |
final int action = ev.getAction (); | |
if (mIsBeingDragged && action == MotionEvent.ACTION_MOVE) {//当已经处于拖动,并且当前事件是MOVE,直接消费掉 | |
return true; | |
} | |
switch (action) { | |
case MotionEvent.ACTION_DOWN: { | |
final float x = ev.getX (); | |
mLastMotionX = x; //记录住当前的x坐标 | |
mIsBeingDragged = !mScroller.isFinished ();//如果按下的时候还在滚动,则把状态处于拖动状态 | |
LogUtils.d ("onInterceptTouchEvent--->mIsBeingDragged:"+mIsBeingDragged); | |
break; | |
} | |
case MotionEvent.ACTION_MOVE: { | |
final float x = ev.getX (); | |
final int xDiff = (int) Math.abs (x - mLastMotionX);//计算两次的差值 | |
if (xDiff > mTouchSlop) {//如果大于最小移动的距离,则把状态改变为拖动状态 | |
mIsBeingDragged = true; | |
mLastMotionX = x; | |
ViewParent parent = getParent ();//并请求父View不要再拦截自己触摸事件,交给自己处理 | |
if (parent != null) { | |
parent.requestDisallowInterceptTouchEvent (true); | |
} | |
} | |
break; | |
} | |
case MotionEvent.ACTION_CANCEL://当手指离开或者触摸事件取消的时候,把拖动状态取消掉 | |
case MotionEvent.ACTION_UP: | |
mIsBeingDragged = false; | |
break; | |
} | |
LogUtils.d ("onInterceptTouchEvent--->mIsBeingDragged before return :"+mIsBeingDragged); | |
return mIsBeingDragged;//如果是拖动状态,则拦截事件,交给自己的onTouch处理 | |
} | |
/** | |
* 触摸事件的处理方法 | |
*/ | |
public boolean onTouchEvent(MotionEvent ev) { | |
if (mVelocityTracker == null) { | |
mVelocityTracker = VelocityTracker.obtain (); | |
} | |
mVelocityTracker.addMovement (ev); | |
final int action = ev.getAction (); | |
switch (action) { | |
case MotionEvent.ACTION_DOWN: {//如果是down事件,记录住当前的x坐标 | |
final float x = ev.getX (); | |
if (!mScroller.isFinished ()) { | |
mScroller.abortAnimation (); | |
} | |
mLastMotionX = x; | |
break; | |
} | |
case MotionEvent.ACTION_MOVE: { | |
final float x = ev.getX (); | |
final float deltaX = x - mLastMotionX; | |
// if (!mIsBeingDragged) {//如果还没有处于拖动,则判断两次的差值是否大于最小拖动的距离 | |
// if (Math.abs (deltaX) > mTouchSlop) { | |
// mIsBeingDragged = true; | |
// } | |
// } | |
if (mIsBeingDragged) {//如果处于拖动状态,记录住x坐标 | |
mLastMotionX = x; | |
onMove (deltaX); | |
} | |
break; | |
} | |
case MotionEvent.ACTION_UP: { | |
if (mIsBeingDragged) { | |
final VelocityTracker velocityTracker = mVelocityTracker; | |
//先对速度进行一个调整,第一个参数是时间单位,1000毫秒,第二个参数是最大速度。 | |
velocityTracker.computeCurrentVelocity (1000, mMaximumVelocity); | |
float velocity = velocityTracker.getXVelocity ();//获取水平方向上的速度 | |
onUp (velocity); | |
} | |
} | |
case MotionEvent.ACTION_CANCEL: { | |
mIsBeingDragged = false; | |
if (mVelocityTracker != null) { | |
mVelocityTracker.recycle (); | |
mVelocityTracker = null; | |
} | |
break; | |
} | |
} | |
return true; | |
} | |
private void onMove(float x) { | |
if (mMaxScrollX <= 0) { | |
if (mViewPager.isFakeDragging () || mViewPager.beginFakeDrag ()) { //模拟ViewPager的拖拽效果 | |
mViewPager.fakeDragBy (x); | |
} | |
} else { | |
int scrollByX = -(int) (x + 0.5); | |
if (getScrollX () + scrollByX < 0) { | |
scrollByX = 0 - getScrollX (); | |
mLeftEdge.onPull (Math.abs (x) / getWidth ()); | |
} | |
if (getScrollX () + scrollByX > mMaxScrollX) { | |
scrollByX = mMaxScrollX - getScrollX (); | |
mRightEdge.onPull (Math.abs (x) / getWidth ()); | |
} | |
scrollBy (scrollByX, 0); | |
ViewCompat.postInvalidateOnAnimation (this); | |
} | |
} | |
private void onUp(float velocity) { | |
if (mMaxScrollX <= 0) { | |
if (mViewPager.isFakeDragging ()) mViewPager.endFakeDrag (); | |
} else { | |
if (Math.abs (velocity) <= mMinimumVelocity) { | |
return; | |
} | |
mScroller.fling (getScrollX (), 0, -(int) (velocity + 0.5), 0, 0, mMaxScrollX, 0, 0, 270, 0); | |
ViewCompat.postInvalidateOnAnimation (this); | |
} | |
} | |
@Override | |
public void computeScroll() { | |
if (!mScroller.isFinished() && mScroller.computeScrollOffset ()) { | |
int oldX = mLastScrollX; | |
mLastScrollX = mScroller.getCurrX (); | |
if (mLastScrollX < 0 && oldX >= 0) { | |
mLeftEdge.onAbsorb ((int) mScroller.getCurrVelocity ()); | |
} else if (mLastScrollX > mMaxScrollX && oldX <= mMaxScrollX) { | |
mRightEdge.onAbsorb ((int) mScroller.getCurrVelocity ()); | |
} | |
int x = mLastScrollX; | |
if (mLastScrollX < 0) { | |
x = 0; | |
} else if (mLastScrollX > mMaxScrollX) { | |
x = mMaxScrollX; | |
} | |
scrollTo (x, 0); | |
ViewCompat.postInvalidateOnAnimation (this); | |
} | |
} | |
/** | |
* 检测mIndicatorOffset的合法性,并计算出其他有关tab的属性值 | |
*/ | |
private void checkAndcalculate() { | |
// 如果指示器起始位置比第一个tab的起始位置还要小,纠正为第一个tab的起始位置,指示器宽度就是第一个tab的宽度 | |
final View firstTab = getChildAt (0); | |
if (mIndicatorLeft < firstTab.getLeft ()) { | |
mIndicatorLeft = firstTab.getLeft (); | |
mIndicatorWidth = firstTab.getWidth (); | |
} | |
// 如果指示器起始位置比最后一个tab的起始位置还要大,纠正为最后一个tab的起始位置,指示器宽度就是最后一个tab的宽度 | |
View lastTab = getChildAt (mTabCount - 1); | |
if (mIndicatorLeft > lastTab.getLeft ()) { | |
mIndicatorLeft = lastTab.getLeft (); | |
mIndicatorWidth = lastTab.getWidth (); | |
} | |
// 通过指示器的起始位置计算出当前处于第几个position,并且计算出已经偏移了多少,偏移量是以当前所处的tab的宽度的百分比 | |
for(int i = 0; i < mTabCount; i++) { | |
View tab = getChildAt (i); | |
if (mIndicatorLeft < tab.getLeft ()) { | |
mCurrentPosition = i - 1; | |
View currentTab = getChildAt (mCurrentPosition); | |
mCurrentOffsetPixels = (mIndicatorLeft - currentTab.getLeft ()) / (currentTab.getWidth () + 0.0f); | |
break; | |
} | |
} | |
} | |
/** | |
* 滚动到指定的child | |
*/ | |
public void scrollSelf(int position, float offset) { | |
if (position >= mTabCount) { | |
return; | |
} | |
final View tab = getChildAt (position); | |
mIndicatorLeft = (int) (tab.getLeft () + tab.getWidth () * offset + 0.5); | |
int rightPosition = position + 1; | |
if (offset > 0 && rightPosition < mTabCount) { | |
View rightTab = getChildAt (rightPosition); | |
mIndicatorWidth = (int) (tab.getWidth () * (1 - offset) + rightTab.getWidth () * offset + 0.5); //Indicator的宽度根据Viewpager的offset决定 | |
} else { | |
mIndicatorWidth = tab.getWidth (); | |
} | |
checkAndcalculate (); | |
int newScrollX = position * mSplitScrollX + (int) (offset * mSplitScrollX + 0.5); | |
if (newScrollX < 0) { | |
newScrollX = 0; | |
} | |
if (newScrollX > mMaxScrollX) { | |
newScrollX = mMaxScrollX; | |
} | |
int duration = 100; | |
if (mSelectedPosition != -1) { | |
duration = (Math.abs (mSelectedPosition - position)) * 100; | |
} | |
mScroller.startScroll (getScrollX (), 0, (newScrollX - getScrollX ()), 0, duration); | |
ViewCompat.postInvalidateOnAnimation (this); | |
} | |
/** | |
* 选中指定位置的Tab | |
*/ | |
private void selectTab(int position) { | |
for(int i = 0; i < mTabCount; i++) { | |
View tab = getChildAt (i); | |
if (tab != null) { | |
tab.setSelected (position == i); | |
} | |
} | |
} | |
/** | |
* ViewPager的OnPageChangeListener实现类,因为我们需要在PagerTab中获取PagerView的监听,以便可以调整tab | |
*/ | |
private class PageListener implements OnPageChangeListener { | |
@Override | |
public void onPageScrolled(int position, float positionOffset, final int positionOffsetPixels) { | |
//根据VierPager的偏移值来滚动tab | |
scrollSelf (position, positionOffset); | |
if (mDelegatePageListener != null) {//这个是提供给外部的 | |
mDelegatePageListener.onPageScrolled (position, positionOffset, positionOffsetPixels); | |
} | |
} | |
@Override | |
public void onPageScrollStateChanged(int state) { | |
if (state == ViewPager.SCROLL_STATE_IDLE) { | |
mSelectedPosition = -1; | |
} | |
if (mDelegatePageListener != null) { | |
mDelegatePageListener.onPageScrollStateChanged (state); | |
} | |
} | |
@Override | |
public void onPageSelected(int position) { | |
LogUtils.d ("PagerTab-> onPageSelected:" + position); | |
mSelectedPosition = position; | |
selectTab (position); | |
if (mDelegatePageListener != null) { | |
mDelegatePageListener.onPageSelected (position); | |
} | |
} | |
} | |
/** | |
* 如果指示器希望是图片,则继承该接口 | |
*/ | |
public interface IconTabProvider { | |
public int getPageIconResId(int position); | |
public int getPageSelectedIconResId(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment