您的位置:首页 > 移动开发 > Android开发

PagerSlidingTabStrip源码解析

2017-06-27 17:44 357 查看

PagerSlidingTabStrip源码解析

集成使用

导包

在Android Studio中,直接在build.gradle文件中增加如下依赖:

dependencies {
compile 'com.astuetz:pagerslidingtabstrip:1.0.1'
}


XML文件布局

在XML文件中使用时,PagerSlidingTabStrip通常声明在ViewPager的上方.

<com.yunos.sprd.appstore.widget.PagerSlidingTabStrip
android:id="@+id/tabs"
android:layout_width="match_parent"
android:layout_height="@dimen/title_page_indicator_height"
android:background="@color/colorCCFF7E3B"
android:textColor="@android:color/white"
android:textSize="@dimen/tab_title_textsize"
android:focusable="true"
app:pstsActivateTextColor="@color/colorFFFFFFFF"
app:pstsDeactiveTextColor="@color/color99FFFFFF"
app:pstsIndicatorColor="@android:color/white"
app:pstsIndicatorHeight="@dimen/psts_indicator_height"
app:pstsShouldExpand="true"
app:pstsTabSwitch="true"
app:pstsTabPaddingLeftRight="0px"/>

<android.support.v4.view.ViewPager
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />


Activity或Fragment中初始化

在Activity的onCreate方法中(或者Fragment的onCreateView)中,绑定PagerSlidingTabStrip到ViewPager.

// Initialize the ViewPager and set an adapter
ViewPager pager = (ViewPager) findViewById(R.id.pager);
pager.setAdapter(new TestAdapter(getSupportFragmentManager()));

// Bind the tabs to the ViewPager
PagerSlidingTabStrip tabs = (PagerSlidingTabStrip) findViewById(R.id.tabs);
tabs.setViewPager(pager);

// set OnPageChangeListener on PagerSlidingTabStrip instead of ViewPager
tabs.setOnPageChangeListener(mPageChangeListener);


源码分析

构造函数

PagerSlidingTabStrip在构造函数中主要是对变量进行初始化:

public PagerSlidingTabStrip(Context context) {
this(context, null);
}

public PagerSlidingTabStrip(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}

public PagerSlidingTabStrip(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);

// 允许组件中的控件去充满自己
setFillViewport(true);
setWillNotDraw(false);

// 定义一个横向的LinearLayout
tabsContainer = new LinearLayout(context);
tabsContainer.setOrientation(LinearLayout.HORIZONTAL);
tabsContainer.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
addView(tabsContainer);

DisplayMetrics dm = getResources().getDisplayMetrics();

// 获取预设的属性值
scrollOffset = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, scrollOffset, dm);
indicatorHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, indicatorHeight, dm);
underlineHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, underlineHeight, dm);
dividerPadding = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dividerPadding, dm);
tabPadding = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, tabPadding, dm);
dividerWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dividerWidth, dm);
tabTextSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, tabTextSize, dm);

// get system attrs (android:textSize and android:textColor)
TypedArray a = context.obtainStyledAttributes(attrs, ATTRS);
tabTextSize = a.getDimensionPixelSize(0, tabTextSize);
tabTextColor = a.getColor(1, tabTextColor);
a.recycle();

// 获取自定义属性值
a = context.obtainStyledAttributes(attrs, R.styleable.PagerSlidingTabStrip);
indicatorColor = a.getColor(R.styleable.PagerSlidingTabStrip_pstsIndicatorColor, indicatorColor);
underlineColor = a.getColor(R.styleable.PagerSlidingTabStrip_pstsUnderlineColor, underlineColor);
dividerColor = a.getColor(R.styleable.PagerSlidingTabStrip_pstsDividerColor, dividerColor);
indicatorHeight = a.getDimensionPixelSize(R.styleable.PagerSlidingTabStrip_pstsIndicatorHeight, indicatorHeight);
underlineHeight = a.getDimensionPixelSize(R.styleable.PagerSlidingTabStrip_pstsUnderlineHeight, underlineHeight);
dividerPadding = a.getDimensionPixelSize(R.styleable.PagerSlidingTabStrip_pstsDividerPadding, dividerPadding);
tabPadding = a.getDimensionPixelSize(R.styleable.PagerSlidingTabStrip_pstsTabPaddingLeftRight, tabPadding);
tabBackgroundResId = a.getResourceId(R.styleable.PagerSlidingTabStrip_pstsTabBackground, tabBackgroundResId);
shouldExpand = a.getBoolean(R.styleable.PagerSlidingTabStrip_pstsShouldExpand, shouldExpand);
scrollOffset = a.getDimensionPixelSize(R.styleable.PagerSlidingTabStrip_pstsScrollOffset, scrollOffset);
textAllCaps = a.getBoolean(R.styleable.PagerSlidingTabStrip_pstsTextAllCaps, textAllCaps);
tabSwitch = a.getBoolean(R.styleable.PagerSlidingTabStrip_pstsTabSwitch, tabSwitch);
tabActiveTextColor = a.getColor(R.styleable.PagerSlidingTabStrip_pstsActivateTextColor, tabActiveTextColor);
tabDeactiveTextColor = a.getColor(R.styleable.PagerSlidingTabStrip_pstsDeactiveTextColor, tabDeactiveTextColor);
a.recycle();

// Tab的滑动指示器画笔
rectPaint = new Paint();
rectPaint.setAntiAlias(true);
rectPaint.setStyle(Style.FILL);

// 垂直分隔线的画笔
dividerPaint = new Paint();
dividerPaint.setAntiAlias(true);
dividerPaint.setStrokeWidth(dividerWidth);

// 设置默认的Tab属性
defaultTabLayoutParams = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
// 设置均分的tab属性
expandedTabLayoutParams = new LinearLayout.LayoutParams(0, LayoutParams.MATCH_PARENT, 1.0f);

if (locale == null) {
locale = getResources().getConfiguration().locale;
}
}


onDraw方法实现

中文注释的onDraw函数源码如下:

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);

if (isInEditMode() || tabCount == 0) {
return;
}

final int height = getHeight();

// 设置滑动指示器画笔的颜色
rectPaint.setColor(indicatorColor);

// 获取当前的Tab,确定Tab的左右坐标,在当前Tab的下面绘制指示器
View currentTab = tabsContainer.getChildAt(currentPosition);
float lineLeft = currentTab.getLeft();
float lineRight = currentTab.getRight();

// 如果ViewPager存在滑动偏移量,则需要根据偏移量来更新Tab的左右坐标
// currentPositionOffset为float,介于0~1,代表相对于tab宽的偏移比例
if (currentPositionOffset > 0f && currentPosition < tabCount - 1) {

View nextTab = tabsContainer.getChildAt(currentPosition + 1);
final float nextTabLeft = nextTab.getLeft();
final float nextTabRight = nextTab.getRight();

lineLeft = (currentPositionOffset * nextTabLeft + (1f - currentPositionOffset) * lineLeft);
lineRight = (currentPositionOffset * nextTabRight + (1f - currentPositionOffset) * lineRight);
}

// 绘制当前tab下面的指示器
canvas.drawRect(lineLeft, height - indicatorHeight, lineRight, height, rectPaint);

// 绘制整个导航栏
rectPaint.setColor(underlineColor);
canvas.drawRect(0, height - underlineHeight, tabsContainer.getWidth(), height, rectPaint);

// 绘制垂直分隔线
dividerPaint.setColor(dividerColor);
for (int i = 0; i < tabCount - 1; i++) {
View tab = tabsContainer.getChildAt(i);
canvas.drawLine(tab.getRight(), dividerPadding, tab.getRight(), height - dividerPadding, dividerPaint);
}
}


联动实现

接下来,我们进入绘制的关键代码。PagerSlidingTabStrip是如何与ViewPager实现滑动联动的.

PagerSlidingTabStrip之所以能实现和ViewPager的联动,是因为它引用了ViewPager的OnPageChangeListener.关键代码:

public void setViewPager(ViewPager pager) {
this.pager = pager;

if (pager.getAdapter() == null) {
throw new IllegalStateException("ViewPager does not have adapter instance.");
}

pager.addOnPageChangeListener(pageListener);

notifyDataSetChanged();
}


从代码中,我们可以分析出:PagerSlidingTabStrip保持了ViewPager的句柄,同时为ViewPager设置了一个OnPageChangeListener接口.

这个接口的中文注释源码如下:

/**
* delegatePageListener是用户设置的OnPageChangeListener,因为不响应滑动实现,我将其代码删除了.
*/
private class PageListener implements OnPageChangeListener {

/**
* 这个方法在屏幕滚动时不断被调用
* @param position 当前页面.
* @param positionOffset 当前页面的偏移比例.如果页面向右翻动,这个值不断变大,最后在趋近于1的情况下突变为0.如果页面向左翻动,这个值不断变小,最后Wie0.
* @param positionOffsetPixels 当前页面因为滑动偏移了多少像素.
*/
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

currentPosition = position;
currentPositionOffset = positionOffset;
// 根据View的位置和偏移量,来同步LinearLayout容器中tab的位置和偏移量
scrollToChild(position, (int) (positionOffset * tabsContainer.getChildAt(position).getWidth()));

invalidate();
}

@Override
public void onPageScrollStateChanged(int state) {
if (state == ViewPager.SCROLL_STATE_IDLE) {
scrollToChild(pager.getCurrentItem(), 0);
}
}

@Override
public void onPageSelected(int position) {
if (tabSwitch) {
updateActivateTab(position);
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android