博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android 快速实现 ViewPager 滑动页卡切换(可用作整个 app上导航)
阅读量:7235 次
发布时间:2019-06-29

本文共 7375 字,大约阅读时间需要 24 分钟。

http://blog.csdn.net/jxxfzgy/article/details/44162211

效果:

今天这篇 blog的内容同样可以拿来做 app 的整体架构,但与前面那篇 blog 不同,不同之处是前面那篇文章所讲的内容可用作底部导航,而这篇 blog 的内容,是用作顶部导航,老版本的微信就是此效果,ok,来看看效果图 

这里写图片描述

实现原理

根据效果图,不难分析,可以通过自定义 ViewGroup 来实现,但这样代码量偏多,看了我的前面 blog 的朋友应该清楚,这里最好的实现方式是通过重写 LinearLayout,相比通过 ViewGroup 来实现,省略了测量onMeasure()和布局onLayout()方法的实现,因为这些LinearLayout已经帮我们实现好了,而我们真正要做的就是为 LinearLayout 填充内容,填充内容可大致可分为以下四个步骤:

1、填充每个 item 的内容

2、绘制每个 item 之间的分割线

3、绘制底部线条

4、绘制指示器的内容

代码实现

1、先把需要用的属性定义出来 

需要的属性 
1、页卡指示器的颜色 
2、分割线的颜色 
3、底部线条的颜色 
4、页卡指示器的高度 
5、分割线距离上下边距的距离 
6、分割线的宽度

2、代码中获取属性,并附上相应的默认值

/*默认的页卡颜色*/    private final int DEFAULT_INDICATOR_COLOR = 0xffff00ff;    /*默认分割线的颜色*/    private final int DEFAULT_DIVIDER_COLOR = 0xff000000;    /*默认title字体的大小*/    private final int DEFAULT_TEXT_SIZE = 16;    /*默认padding*/    private final int DEFAULT_TEXT_PADDING = 16;    /*divider默认的宽度*/    private final int DEFAULT_DIVIDER_WIDTH = 1;    /*indicator 的高度*/    private final int DEFAULT_INDICATOR_HEIGHT = 5;    /*底部线条的高度默认值*/    private final int DEFAULT_BOTTOM_LINE_HEIGHT = 2;    /*分割线距离上下边缘的距离默认为8*/    private final int DEFAULT_DIVIDER_MARGIN = 8;    /*底部线条的颜色默认值*/    private final int DEFAULT_BOTTOM_LINE_COLOR = 0xff000000;/*获取TypedArray*/        TypedArray typedArray = getResources().obtainAttributes(attrs, R.styleable.SlidingTabLayout);        /*获取自定义属性的个数*/        int N = typedArray.getIndexCount();        Log.v("zgy","=========getIndexCount========="+N) ;        for (int i = 0; i < N; i++) {            int attr = typedArray.getIndex(i);            switch (attr) {                case R.styleable.SlidingTabLayout_indicatorColor:                    /*获取页卡颜色值*/                    mIndicatorColor = typedArray.getColor(attr, DEFAULT_INDICATOR_COLOR);                    break;                case R.styleable.SlidingTabLayout_dividerColor:                    /*获取分割线颜色的值*/                    mDividerColor = typedArray.getColor(attr, DEFAULT_DIVIDER_COLOR);                    break;                case R.styleable.SlidingTabLayout_bottomLineColor:                    /*获取底部线条颜色的值*/                    mBottomLineColor = typedArray.getColor(attr, DEFAULT_BOTTOM_LINE_COLOR);                    break;                case R.styleable.SlidingTabLayout_dividerMargin:                    /*获取分割线的距离上线边距的距离*/                    mDividerMargin = (int) typedArray.getDimension(attr, DEFAULT_DIVIDER_MARGIN * getResources().getDisplayMetrics().density);                    Log.v("zgy","=========mDividerMargin========="+mDividerMargin) ;                    break;                case R.styleable.SlidingTabLayout_indicatorHeight:                    /*获取页卡的高度*/                    mIndicatorHeight = (int) typedArray.getDimension(attr, DEFAULT_INDICATOR_HEIGHT * getResources().getDisplayMetrics().density);                    break;                case R.styleable.SlidingTabLayout_bottomLineHeight:                    /*获取底部线条的高度*/                    mBottomLineHeight = (int) typedArray.getDimension(attr, DEFAULT_BOTTOM_LINE_HEIGHT * getResources().getDisplayMetrics().density);                    break;                case R.styleable.SlidingTabLayout_dividerWidth:                    /*获取分割线的宽度*/                    mDividerWidth = (int) typedArray.getDimension(attr, DEFAULT_DIVIDER_WIDTH * getResources().getDisplayMetrics().density);                    break;            }        }        /*释放TypedArray*/        typedArray.recycle();

这里说一个细节,我经常在这里获取属性的时候习惯性的把

case R.styleable.SlidingTabLayout_indicatorColor:

写成

case R.attr.indicatorColor:

而且这里不会报错,不过结果可想而知,无法获取我们设置的属性内容,这里如果有跟我犯同样错误的朋友记得注意一下。

3、为 LinearLayout 填充内容

/**     * 设置viewPager,初始化SlidingTab,     * 在这个方法中为SlidingLayout设置     * 内容,     *     * @param viewPager     */    public void setViewPager(ViewPager viewPager) {        /*先移除所以已经填充的内容*/        removeAllViews();        /* viewPager 不能为空*/        if (viewPager == null) {            throw new RuntimeException("ViewPager不能为空");        }        mViewPager = viewPager;        mViewPager.setOnPageChangeListener(new InternalViewPagerChange());        //填充内容        populateTabLayout();    } /**     * 填充layout,设置其内容     */    private void populateTabLayout() {        final PagerAdapter adapter = mViewPager.getAdapter();        final OnClickListener tabOnClickListener = new TabOnClickListener();        mItemName = (TabItemName) adapter;        for (int i = 0; i < adapter.getCount(); i++) {            TextView textView = createDefaultTabView(getContext());            textView.setOnClickListener(tabOnClickListener);            textView.setText(mItemName.getTabName(i));            addView(textView);        }    }

根据ViewPager中页面的个数,填充相应的 tab。

4、绘制相应的内容 

绘制内容,肯定在 onDraw()方法中 
绘制底部线条

canvas.drawRect(0,height - mBottomLineHeight,getWidth(),height,mBottomPaint);

绘制分割线

for (int i = 0; i < getChildCount() - 1; i++) {      View child = getChildAt(i);      canvas.drawLine(child.getRight(), mDividerMargin,child.getRight(), height - mDividerMargin,mDividerPaint);        }

重点:绘制滑动页卡

/*当前页面的View tab*/        View selectView = getChildAt(mSelectedPosition);        /*计算开始绘制的位置*/        int left = selectView.getLeft();        /*计算结束绘制的位置*/        int right = selectView.getRight();        if (mSelectionOffset > 0) {            View nextView = getChildAt(mSelectedPosition + 1);            /*如果有偏移量,重新计算开始绘制的位置*/            left = (int) (mSelectionOffset * nextView.getLeft() + (1.0f - mSelectionOffset) * left);            /*如果有偏移量,重新计算结束绘制的位置*/            right = (int) (mSelectionOffset * nextView.getRight() + (1.0f - mSelectionOffset) * right);        }        /*绘制滑动的页卡*/        canvas.drawRect(left, height - mIndicatorHeight, right, height, mIndicatorPaint);

运用案例

为了体现他的简洁之处,这里把 xml 中的代码也贴出来

MainActivity.java

public class MainActivity extends ActionBarActivity {    /*viewPager*/    private ViewPager mViewPager ;    /*自定义的 tabLayout*/    private SlidingTabLayout mTabLayout ;    /*每个 tab 的 item*/    private List
mTab = new ArrayList<>() ; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mViewPager = (ViewPager) findViewById(R.id.id_view_pager) ; mTabLayout = (SlidingTabLayout) findViewById(R.id.id_tab) ; mTab.add(new PagerItem("tab1","FirstPager")) ; mTab.add(new PagerItem("tab2","SecondPager")) ; mTab.add(new PagerItem("tab3","ThirdPager")) ; mTab.add(new PagerItem("tab4","FourthPager")) ; mViewPager.setAdapter(new ViewPagerAdapter(getSupportFragmentManager())); /*需要先为 viewpager 设置 adapter*/ mTabLayout.setViewPager(mViewPager); } private class ViewPagerAdapter extends FragmentPagerAdapter implements SlidingTabLayout.TabItemName{ public ViewPagerAdapter(FragmentManager fm) { super(fm); } @Override public Fragment getItem(int position) { return mTab.get(position).createFragment(); } @Override public int getCount() { return mTab.size(); } @Override public String getTabName(int position) { return mTab.get(position).getTitle();

你可能感兴趣的文章
postgresql 清空数据表 truncate
查看>>
原来这样就可以开发出一个百万量级的Android相机
查看>>
MySQL执行计划分析
查看>>
素材网
查看>>
在Salesforce中向外公布Service去创建Lead,并且用Asp.Net去调用此Service
查看>>
Mb与MB的区别
查看>>
使用python开发hadoop streaming程序及hadoop python网页抓取例子
查看>>
MySql主主(主从)同步配置详解
查看>>
Mysql 关键字及保留字
查看>>
解析text文本【2】——从数据库读入
查看>>
【配置文件】什么是log4j.properties 怎么配置
查看>>
在linux下使用wc来统计文件行数
查看>>
尚学堂java相关
查看>>
在些时候,放弃治疗或许是最好的选择
查看>>
ASP.NET MVC文章附加有源码下载的文章
查看>>
省时的浏览器同步测试工具 browsersync NodeJS
查看>>
Java数据库连接——JDBC调用存储过程,事务管理和高级应用
查看>>
如何取消Excel中的自动超链接
查看>>
随机森林——Random Forests
查看>>
如何使用Git上传项目代码到代码服务器
查看>>