使用PagerSlidingTabStrip实现顶部导航栏
来源:互联网 发布:mac合盖屏幕亮 编辑:程序博客网 时间:2024/05/24 01:55
在开发中,我们有时会遇到顶部导航栏滑动切换页面的设计,如网易新闻。实现的方式有很多种,今天我们使用PagerSlidingTabStrip配合ViewPager实现顶部导航栏。
效果图如下。
PagerSlidingTabStrip是github上的一个开源项目,项目地址如下。
https://github.com/astuetz/PagerSlidingTabStrip
(一)PagerSlidingTabStrip的使用
在使用之前,我们先来看一下PagerSlidingTabStrip中的自定义属性。
各属性的详细介绍如下。
pstsIndicatorColor:滑动条的颜色。
pstsIndicatorHeight:滑动条的高度。
pstsUnderlineColor:底部线条的颜色。(底部线条会填充屏幕宽度)
pstsUnderlineHeight:底部线条的高度。
pstsDividerColor:tab之间的竖直分割线的颜色。
pstsDividerPadding:tab之间的竖直分割线,距离顶部和底部的距离,即它的paddingTop和paddingBottom。
pstsTabPaddingLeftRight:单个tab内部的左间距和右间距,即它的paddingLeft和paddingRight。
pstsTabBackground:单个tab的背景。
pstsScrollOffset:当前tab滚动的偏移量。
pstsShouldExpand:设置为ture,每个tab的权重一样,均分屏幕宽度,默认值false。
pstsTextAllCaps:是否将tab中的字母转换成大写,默认值true。
接下来添加布局文件。
(二)PagerSlidingTabStrip的源码分析
(1).类的声明。
PagerSlidingTabStrip继承自HorizontalScrillView,当tab数量较多超出屏幕时,可以横向滚动。
(2).构造方法。
在构造方法中,先是创建了一个水平线性布局tabsContainer,并将其添加到PagerSlidingTabStrip中。因为PagerSlidingTabStrip继承自HorizontalScrillView,而HorizontalScrillView内部只能有一个子View,所以之后的tab都将添加到tabsContainer布局中。
接下来创建了两个画笔rectPaint和dividerPaint,分别用来绘制滑动条和竖直分隔线。
最后创建了两个布局参数LayoutParams,默认为defaultTabLayoutParams,自适应tab的宽度,以及expandedTabLayoutParams,tab均分屏幕宽度。当自定义属性pstsShouldExpand声明为true时,使用expandedTabLayoutParams,相反则使用defaultTabLayoutParams。
(3).setViewPager(ViewPager pager)方法。
方法内部,遍历ViewPager的Adapter中的标题,生成Tab并添加到tabsContainer布局中。然后将滑动条滚动到第一个Tab下。
(5).OnPageChangeListener的实现类,PageListener类。
PageListener类监听ViewPager的滑动。
通过在onPageScrolled()回调方法中得到的currentPosition和currentPositionOffset,实时绘制滑动条的位置,实现滑动条跟随手势移动。
最后附上完整工程下载链接。
http://download.csdn.net/detail/ruancoder/9582974
效果图如下。
PagerSlidingTabStrip是github上的一个开源项目,项目地址如下。
https://github.com/astuetz/PagerSlidingTabStrip
(一)PagerSlidingTabStrip的使用
在使用之前,我们先来看一下PagerSlidingTabStrip中的自定义属性。
<declare-styleable name="PagerSlidingTabStrip"> <attr name="pstsIndicatorColor" format="color" /> <attr name="pstsUnderlineColor" format="color" /> <attr name="pstsDividerColor" format="color" /> <attr name="pstsIndicatorHeight" format="dimension" /> <attr name="pstsUnderlineHeight" format="dimension" /> <attr name="pstsDividerPadding" format="dimension" /> <attr name="pstsTabPaddingLeftRight" format="dimension" /> <attr name="pstsScrollOffset" format="dimension" /> <attr name="pstsTabBackground" format="reference" /> <attr name="pstsShouldExpand" format="boolean" /> <attr name="pstsTextAllCaps" format="boolean" /></declare-styleable>
各属性的详细介绍如下。
pstsIndicatorColor:滑动条的颜色。
pstsIndicatorHeight:滑动条的高度。
pstsUnderlineColor:底部线条的颜色。(底部线条会填充屏幕宽度)
pstsUnderlineHeight:底部线条的高度。
pstsDividerColor:tab之间的竖直分割线的颜色。
pstsDividerPadding:tab之间的竖直分割线,距离顶部和底部的距离,即它的paddingTop和paddingBottom。
pstsTabPaddingLeftRight:单个tab内部的左间距和右间距,即它的paddingLeft和paddingRight。
pstsTabBackground:单个tab的背景。
pstsScrollOffset:当前tab滚动的偏移量。
pstsShouldExpand:设置为ture,每个tab的权重一样,均分屏幕宽度,默认值false。
pstsTextAllCaps:是否将tab中的字母转换成大写,默认值true。
下面,我们将PagerSlidingTabStrip使用到具体项目中。
dependencies { compile 'com.astuetz:pagerslidingtabstrip:1.0.1'}
接下来添加布局文件。
<com.astuetz.PagerSlidingTabStrip xmlns:tab="http://schemas.android.com/apk/res-auto" android:id="@+id/tab" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#fafafa" android:paddingBottom="10dp" android:paddingTop="10dp" android:textColor="#333333" android:textSize="13sp" tab:pstsDividerColor="@android:color/transparent" tab:pstsIndicatorColor="#ed5955" tab:pstsIndicatorHeight="2dp" tab:pstsShouldExpand="true" tab:pstsTabBackground="@android:color/transparent" tab:pstsUnderlineColor="@android:color/transparent"/>
最后实现逻辑代码。
package net.csdn.blog.ruancoder;import android.os.Bundle;import android.support.v4.app.Fragment;import android.support.v4.app.FragmentActivity;import android.support.v4.view.ViewPager;import android.view.Window;import com.astuetz.PagerSlidingTabStrip;public class MainActivity extends FragmentActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.activity_main); final PagerSlidingTabStrip tabStrip = (PagerSlidingTabStrip) findViewById(R.id.tab); ViewPager viewPager = (ViewPager) findViewById(R.id.viewpager); Fragment[] fragments = {new NewsFragment(), new TechFragment(), new FinanceFragment(), new InternetFragment(), new PhoneFragment()}; String[] titles = {"头条", "科技", "财经", "互联网", "手机"}; TabPagerAdapter adapter = new TabPagerAdapter(getSupportFragmentManager(), fragments, titles); viewPager.setAdapter(adapter); tabStrip.setViewPager(viewPager); }}
Activity中使用到的TabPagerAdapter类:
package net.csdn.blog.ruancoder;import android.support.v4.app.Fragment;import android.support.v4.app.FragmentManager;import android.support.v4.app.FragmentPagerAdapter;public class TabPagerAdapter extends FragmentPagerAdapter { private Fragment[] mFragments; private String[] mTitles; public TabPagerAdapter(FragmentManager fm, Fragment[] fragments, String[] titles) { super(fm); this.mFragments = fragments; this.mTitles = titles; } @Override public Fragment getItem(int position) { return mFragments[position]; } @Override public int getCount() { return mFragments.length; } @Override public CharSequence getPageTitle(int position) { return mTitles[position]; }}
(二)PagerSlidingTabStrip的源码分析
(1).类的声明。
package com.astuetz;public class PagerSlidingTabStrip extends HorizontalScrollView {}
PagerSlidingTabStrip继承自HorizontalScrillView,当tab数量较多超出屏幕时,可以横向滚动。
(2).构造方法。
public PagerSlidingTabStrip(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); tabsContainer = new LinearLayout(context); tabsContainer.setOrientation(LinearLayout.HORIZONTAL); tabsContainer.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); addView(tabsContainer); // 这里省略了初始化各参数的代码 rectPaint = new Paint(); rectPaint.setAntiAlias(true); rectPaint.setStyle(Style.FILL); dividerPaint = new Paint(); dividerPaint.setAntiAlias(true); dividerPaint.setStrokeWidth(dividerWidth); defaultTabLayoutParams = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT); expandedTabLayoutParams = new LinearLayout.LayoutParams(0, LayoutParams.MATCH_PARENT, 1.0f); }
在构造方法中,先是创建了一个水平线性布局tabsContainer,并将其添加到PagerSlidingTabStrip中。因为PagerSlidingTabStrip继承自HorizontalScrillView,而HorizontalScrillView内部只能有一个子View,所以之后的tab都将添加到tabsContainer布局中。
接下来创建了两个画笔rectPaint和dividerPaint,分别用来绘制滑动条和竖直分隔线。
最后创建了两个布局参数LayoutParams,默认为defaultTabLayoutParams,自适应tab的宽度,以及expandedTabLayoutParams,tab均分屏幕宽度。当自定义属性pstsShouldExpand声明为true时,使用expandedTabLayoutParams,相反则使用defaultTabLayoutParams。
(3).setViewPager(ViewPager pager)方法。
public void setViewPager(ViewPager pager) {this.pager = pager;if (pager.getAdapter() == null) {throw new IllegalStateException("ViewPager does not have adapter instance.");}pager.setOnPageChangeListener(pageListener);notifyDataSetChanged();}
当我们获取到PagerSlidingTabStrip对象后,会调用它的setViewPager(ViewPager pager)方法。
在该方法内部,为ViewPager对象添加了滑动监听PageListener,并调用了notifyDataSetChanged()方法。
(4).notifyDataSetChanged()方法。
public void notifyDataSetChanged() { tabsContainer.removeAllViews(); tabCount = pager.getAdapter().getCount(); 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()); } } updateTabStyles(); getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @SuppressWarnings("deprecation") @SuppressLint("NewApi") @Override public void onGlobalLayout() { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { getViewTreeObserver().removeGlobalOnLayoutListener(this); } else { getViewTreeObserver().removeOnGlobalLayoutListener(this); } currentPosition = pager.getCurrentItem(); scrollToChild(currentPosition, 0); } }); }
方法内部,遍历ViewPager的Adapter中的标题,生成Tab并添加到tabsContainer布局中。然后将滑动条滚动到第一个Tab下。
(5).OnPageChangeListener的实现类,PageListener类。
private class PageListener implements ViewPager.OnPageChangeListener { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { currentPosition = position; currentPositionOffset = positionOffset; 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) { // ...... } }
PageListener类监听ViewPager的滑动。
这里重点是onPageScrolled()方法,当ViewPager在滑动过程中该方法不断被回调。在其中执行了2行代码,scrollToChild(),移动tab;invalidate(),触发View的onDraw()的调用。
(6).核心方法onDraw()。
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if (isInEditMode() || tabCount == 0) { return; } final int height = getHeight(); // draw indicator line rectPaint.setColor(indicatorColor); // 默认在当前被选中的tab底部绘制滑动条 View currentTab = tabsContainer.getChildAt(currentPosition); float lineLeft = currentTab.getLeft(); float lineRight = currentTab.getRight(); // 如果正在滑动,在当前tab和下一个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); } // 绘制滑动条,滑动条宽度为lineRight - lineLeft,高度为indicatorHeight canvas.drawRect(lineLeft, height - indicatorHeight, lineRight, height, rectPaint); // 绘制底部线条,线条宽度为PagerSlidingTabStrip的宽度,高度为underlineHeight rectPaint.setColor(underlineColor); canvas.drawRect(0, height - underlineHeight, tabsContainer.getWidth(), height, rectPaint); // 在每个tab的右侧,绘制竖直分割线,分割线宽度为dividerWidth,高度为height - dividerPadding * 2 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); } }
通过在onPageScrolled()回调方法中得到的currentPosition和currentPositionOffset,实时绘制滑动条的位置,实现滑动条跟随手势移动。
最后附上完整工程下载链接。
http://download.csdn.net/detail/ruancoder/9582974
0 0
- 使用PagerSlidingTabStrip实现顶部导航栏
- PagerSlidingTabStrip顶部导航栏
- PagerSlidingTabStrip实现网易新闻导航栏效果
- 导PagerSlidingTabStrip库实现导航栏
- 标签导航栏PagerSlidingTabStrip
- Android中使用开源框架PagerSlidingTabStrip实现导航标题
- Android PagerSlidingTabStrip可实现滑动导航栏效果
- 使用Viewpager 和 Fragment实现顶部导航
- Android 实现顶部导航栏demo
- 顶部滑动导航栏的实现
- TabLayout顶部导航栏+ViewPage实现联动
- 利用JQuery实现顶部导航栏功能
- 利用JQuery实现顶部导航栏功能
- TabLayout实现底部顶部导航栏
- TabLayout与viewpager实现顶部导航栏
- 使用 CollapsingToolbarLayout ,可折叠的顶部导航栏
- Android PagerSlidingTabStrip实现顶部栏目点击或滑动切换
- 滑动导航栏(PagerSlidingTabStrip)实践
- spark sql基本使用方法介绍
- 安卓中的动画分类概述
- Ubuntu - VGA 外接显示器调节分辨率1920x1080
- LeetCode之根据升序的单链表构造平衡二叉树
- Python简单的SOCKET编程
- 使用PagerSlidingTabStrip实现顶部导航栏
- POJ2431 探险 解题报告
- JNI学习积累之一 ---- 常用函数大全
- PathMeasure之迷径追踪
- struts2学习笔记(一)
- 关于phpcms栏目列表从N条开始调用数据的问题
- 2016 Multi-University Training Contest 2 Keep On Movin
- ZABBIX中出现的Zabbix BUS discoverer processes 75%解疑
- Spark Transformation —— flatMap算子