一般入门android以后,想提高自己的android水平,个人认为最好的方式就是大量阅读优秀的开源App,例如开源中国的App,我android入门后就有人推荐我去看,真是收益非浅,想起刚开始写代码的风格,命名方式就是毫无章法,如果换个人来看你的代码估计分分钟想打写代码的人,换个脾气好的,不打你,就生闷气,最后闷出精神疾病也说不好 哈哈 所以严谨代码风格非常重要(说实话,在真正开发中,我没有贯彻得很好,说什么进度赶的都是屁话,就是一个字懒)
好了,废话不多说~ 这章是讲PagerSlidingTabStrip这个控件,但是我前面非扯开源中国是为何呢?不是别的,就是因为我第一次看到这个控件的地方就是在开源中国看到它用的~
也许有人没看过控件,它其实就是配合viewpage,然后给在当前viewpage的上方显示一个标题,然后标题下方有个滑动块,如果不清楚,看下下图的效果图(未改善之前)
发现这个滑动条并不能跟标题栏对齐,但是UI效果是要滑动块和标题对齐,切滑动的时候,根据下一个滑动目标的标题长度动态得改变其长度,效果如下(改善之后)
是不是很多市面上的app都采用了这种风格的控件?最明显的app就是一些新闻类的app,例如网易新闻,今日头条都是这种效果,不过他们做得更绚丽,但究其本质都是一样的,都是监听viewpage的偏移量然后达到一些动态效果
currentPositionOffset 这个就是viewPage的偏移量,然后监听viewpage的滑动即可得到,代码如下
/**
* 设置ViewPager
*
* @param viewPager ViewPager
*/
public void setViewPager(ViewPager viewPager) {
if (disableViewPager)
return;
this.viewPager = viewPager;
this.viewPager.addOnPageChangeListener(new OnPageChangeListener() {
@Override
public void onPageSelected(int position) {
selectedTab(position);
if (onPageChangeListener != null) {
onPageChangeListener.onPageSelected(position);
}
if (listener != null)
listener.onChanged(position);
}
@Override
public void onPageScrolled(int nextPagePosition,
float positionOffset, int positionOffsetPixels) {
ViewGroup tabsLayout = getTabsLayout();
if (nextPagePosition < tabsLayout.getChildCount()) {
View view = tabsLayout.getChildAt(nextPagePosition);
if (view != null) {
currentPosition = nextPagePosition;
currentPositionOffset = positionOffset;
scrollToChild(nextPagePosition,
(int) (positionOffset * view.getWidth()));
isAllowDraw = true;
invalidate();
}
}
if (onPageChangeListener != null) {
onPageChangeListener.onPageScrolled(nextPagePosition,
positionOffset, positionOffsetPixels);
}
}
@Override
public void onPageScrollStateChanged(int arg0) {
if (onPageChangeListener != null) {
onPageChangeListener.onPageScrollStateChanged(arg0);
}
}
});
requestLayout();
}
得到当前滑动的偏移量,然后就进行绘制
在view进行动态绘制,关绘制滑块键代码如下:
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (disableViewPager)
return;
/* 绘制滑块 */
if (isAllowDraw) {
ViewGroup tabsLayout = getTabsLayout();
if (tabsLayout != null && tabsLayout.getChildCount() > 0
&& slidingBlockDrawable != null) {
View currentTab = tabsLayout.getChildAt(currentPosition);
View nextTab = tabsLayout.getChildAt(currentPosition + 1);
float tabStrinpleft;
float nextTabStrinpleft;
float slidingBlockLeft;
float slidingBlockRight;
float nextTabLeft = 0;
float nextTabRight = 0;
if (currentTab != null) {
if (allowAlignmentl) {
tabStrinpleft = ((RelativeLayout) currentTab).getChildAt(0).getLeft();
slidingBlockLeft = currentTab.getLeft() + tabStrinpleft;
slidingBlockRight = currentTab.getRight() - tabStrinpleft;
if (currentPositionOffset > 0f
&& currentPosition < tabsLayout.getChildCount() - 1) {
if (nextTab != null) {
nextTabStrinpleft = ((RelativeLayout) nextTab).getChildAt(0).getLeft();
nextTabLeft = nextTab.getLeft() + nextTabStrinpleft;
nextTabRight = nextTab.getRight() - nextTabStrinpleft;
}
slidingBlockLeft = (currentPositionOffset * nextTabLeft + (1f - currentPositionOffset)
* slidingBlockLeft);
slidingBlockRight = (currentPositionOffset
* nextTabRight + (1f - currentPositionOffset)
* slidingBlockRight);
} else {
}
} else {
slidingBlockLeft = currentTab.getLeft();
slidingBlockRight = currentTab.getRight();
if (currentPositionOffset > 0f
&& currentPosition < tabsLayout.getChildCount() - 1) {
nextTab = tabsLayout.getChildAt(currentPosition + 1);
if (nextTab != null) {
nextTabLeft = nextTab.getLeft();
nextTabRight = nextTab.getRight();
slidingBlockLeft = (currentPositionOffset * nextTabLeft + (1f - currentPositionOffset)
* slidingBlockLeft);
slidingBlockRight = (currentPositionOffset
* nextTabRight + (1f - currentPositionOffset)
* slidingBlockRight);
}
}
}
slidingBlockDrawable.setBounds((int) slidingBlockLeft, 0,
(int) slidingBlockRight, getHeight());
slidingBlockDrawable.draw(canvas);
}
}
}
}
现在讲讲,关于如何通过偏移量,然后动态得计算出该绘制的坐标
首先获取滑块控件,即slidingBlockDrawable,获取之后,我们算出该绘制的点,然后调用setBounds(int left, int top, int right, int bottom) 即可
绘制的时候,只需要知道left,right的坐标点就行,即slidingBlockLeft 和slidingBlockRight就行
接下来就是很重要的步骤,就是通过偏移量来计算出当前的slidingBlockLeft和slidingBlockRight
在滑动时,先得到当前的slidingBlockLeft和slidingBlockRight,然后计算需要滑向下一个的left和right,即nextTabLeft和nextTabRight,然后根据偏移量 通过公式
slidingBlockLeft = (currentPositionOffset * nextTabLeft + (1f - currentPositionOffset) * slidingBlockLeft); slidingBlockRight = (currentPositionOffset * nextTabRight + (1f - currentPositionOffset) * slidingBlockRight);
计算出slidingBlockLeft和slidingBlockRight,最后
slidingBlockDrawable.setBounds((int) slidingBlockLeft, 0, (int) slidingBlockRight, getHeight()); slidingBlockDrawable.draw(canvas);即可
这个控件使用起来没问题,但是使用的时候需要注意一点,在每次view重新绘制的时候一定要记得强制重绘滑块,不然滑块会没有,在demo有写使用注意
后来在github看到了关于这个控件的改善,是滑动时 对标题字进行渐变 ,点击打开链接,如果喜欢它的风格可以去他那里下
好了,给这个控件的下载地址点击打开链接 (Gradle构建方式,所以最好用as打开)