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

Android 开源项目源码解析 -->PagerSlidingTabStrip 源码解析(十八)

2016-09-28 10:52 639 查看
项目:PagerSlidingTabStrip


1. 总体设计

pagerSlidingTabStrip 实现联动效果的原理是,它引用了 ViewPager 的
OnPageChangeListener
。 但是 viewpager 注册的 listener
不是自身的
OnPageChangeListener
,而是 pagerSlidingTabStrip 内部类
PageListener

通过
PageListener
实现对对 viewpager 和 tab 的封装。从而实现滑动联动效果。 可以设置 tab 的类型为 textview 还是 icon。对于 textview
可设置字库属性。 通过提供方法如滑动指示器 下划线 tab 风格线 tab 权重等达到自定义的效果。


2. 流程图



3. 功能介绍


3.1 特性介绍

兼容 Android 支持库中的 ViewPager 的一个滑动分页指示器的控件。
滑动时实现 TextView 颜色状态的联动
支持文字导航指示,可指定选中的 pager 导航字体属性
支持图片导航指示,可高亮选中 pager 页导航背景
很好的扩展性


3.2 集成及使用指南


3.2.1


在 gradle 中
dependencies {
compile 'com.astuetz:pagerslidingtabstrip:1.0.1'
}


3.2.2 在 layout 布局文件中引入 PagerSlidingTabStrip,通常布局在 viewpager 上面。如下:

<com.astuetz.PagerSlidingTabStrip
android:id="@+id/tabs"
android:layout_width="match_parent"
android:layout_height="48dip" />


3.2.3 在 oncreate 方法中(或 Fragment 的 onCreateView)中,绑定 PagerSlidingTabStrip 到 Viewpager

// 初始化 ViewPager 和 Adapter
ViewPager pager = (ViewPager) findViewById(R.id.pager);
pager.setAdapter(new TestAdapter(getSupportFragmentManager()));

// 绑定 PagerSlidingTabStrip 到 ViewPager 上
PagerSlidingTabStrip tabs = (PagerSlidingTabStrip) findViewById(R.id.tabs);
tabs.setViewPager(pager);


3.2.4 如果你的 view pager 使用到 OnPageChangeListener。你应该通过这个 PagerSlidingTabStrip 控件设置而不是 Viewpager。如下:

// continued from above
tabs.setOnPageChangeListener(mPageChangeListener);


3.3 用户定制

根据你的需要修改下面的值
pstsIndicatorColor
 滑动指示器的颜色
pstsUnderlineColor
 整个 view【PagerSlidingTabStrip】下划线的颜色
pstsDividerColor
 tabs 之间分割线的颜色
pstsIndicatorHeight
 滑动指示器的高度
pstsUnderlineHeight
 整个 View【PagerSlidingTabStrip】下滑线的高度
pstsDivviderPadding
 分割线上部、下部的内间距
pstsTabPaddingLeftRight
 每个 tab 左右内间距
pstsScrollOffset
 选中 tab 的滑动的距离
pstsTabBackground
 每个 tab 的背景图片,使用 StateListDrawable
pstsShouldExpand
 如果设置为 true,每个 tab 的宽度拥有相同的权重
pstsTextAllCaps
 如果设置为 true,所有的 tab 字体转为大写


4. 详细设计


4.1 类详细介绍



4.2 核心方法及功能介绍

pagerSlidingTabStrip 实现联动效果的原理是,它引用了 ViewPager 的 OnPageChangeListener。但是 viewpager 注册的 listener 不是自身的
OnPageChangeListener
,而是
pagerSlidingTabStrip 内部类
PageListener
。通过 PageListener 实现对对 viewpager 和 tab 的封装。从而实现滑动联动效果。下面结合代码详细说明
private class PageListener implements OnPageChangeListener {

@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

//当前 view 的位置也即 tab 的位置
currentPosition = position;
//当前 view 滑动的距离。其中 currentPositionOffset 为 float,介于 0~1 代表相对于 tab 宽偏移的比例
currentPositionOffset = positionOffset;
//根据上面得到的 view 的位置和偏移位置,来同步 tab 的位置和偏移距离。
scrollToChild(position, (int) (positionOffset * tabsContainer.getChildAt(position).getWidth()));
//重绘 view,实现 tab 滑动的效果。
invalidate();
//下面的 delegatePageListener 就是我们设置的 viewpager.setOnPageChangeListener.而现在把它封装在整个 pagerSlidingTabStrip 中,实现 viewpager 滑动的效果。
if (delegatePageListener != null) {
delegatePageListener.onPageScrolled(position, positionOffset, positionOffsetPixels);
}
}

@Override
public void onPageScrollStateChanged(int state) {
//滑动结束。positionOffset 归零
if (state == ViewPager.SCROLL_STATE_IDLE) {
scrollToChild(pager.getCurrentItem(), 0);
}
//调用 viewpager.setOnPageChangeListener
if (delegatePageListener != null) {
delegatePageListener.onPageScrollStateChanged(state);
}
}

@Override
public void onPageSelected(int position) {
//调用 viewpager.setOnPageChangeListener
if (delegatePageListener != null) {
delegatePageListener.onPageSelected(position);
}
}

}


scrollToChild,tab 的滑动位置 实现如下:
private void scrollToChild(int position, int offset) {

if (tabCount == 0) {
return;
}

int newScrollX = tabsContainer.getChildAt(position).getLeft() + offset;

if (position > 0 || offset > 0) {
newScrollX -= scrollOffset;
}

//滑动到的位置。
if (newScrollX != lastScrollX) {
lastScrollX = newScrollX;
scrollTo(newScrollX, 0);
}

}


接下来说下 addTextTab addIconTab。即 tab 是 text 还是 icon。如果是 icon 的话,通过 viewpager 的 adapter 实现接口
IconTabProvider
。来确定
icontab。
for (int i = 0; i < tabCount; i++) {

if (pager.getAdapter() instanceof IconTabProvider) {
addIconTab(i, ((IconTabProvider) pager.getAdapter()).getPageIconResId(i));
} else {
addTextTab(i, pager.getAdapter().getPageTitle(i).toString());
}

}


4.3 View 绘制机制

请参考公共技术点
viewdrawflow部分

在 pagerSlidingTabStrip 中重写了 onDraw 函数 绘画滑动指示器; 绘画整个 tabs 下划线; 绘画 tab 之间间隔线。代码如下
// draw indicator line

rectPaint.setColor(indicatorColor);

// default: line below current tab
View currentTab = tabsContainer.getChildAt(currentPosition);
float lineLeft = currentTab.getLeft();
float lineRight = currentTab.getRight();

// if there is an offset, start interpolating left and right coordinates between current and next 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);
}

canvas.drawRect(lineLeft, height - indicatorHeight, lineRight, height, rectPaint);

// draw underline

rectPaint.setColor(underlineColor);
canvas.drawRect(0, height - underlineHeight, tabsContainer.getWidth(), height, rectPaint);

// draw divider

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);
}



5. 杂谈

该库有很好的自定义性和扩展性。比如修改滑动指示器为一张图片【目前为设定颜色值和高度来决定】


6.参考文献

ViewPagerindicator 源码解析


View 的绘制:

How Android Draws Views
View
绘制流程
Android View 绘制流程
Android 中 View 绘制流程以及 invalidate()等相关方法分析
Android 中 measure 过程、WRAP_CONTENT 详解以及 xml 布局文件解析流程浅析(下)


TOUCH 事件处理

View
事件传递
Andriod 从源码的角度详解 View,ViewGroup 的 Touch 事件的分发机制
Android 中 Touch(触屏)事件传递机制
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: