为了账号安全,请及时绑定邮箱和手机立即绑定

自定义实现带三角下标的TabLayout

标签:
Android

在开发中,我们常常需要ViewPager结合Fragment一起使用,如下图:

5b756e370001e2b304260408.jpg

我们可以使用Design support library库的TabLayout去实现,但是TabLayout只能用横线指示器,如果想要其他指示器,比如三角下标,该控件就不能用了。

我们可以找网上成熟的轮子进行修改,比如:PagerSlidingTabStrip

实现了一个类似于今日头条的可滑动tab,带三角下标,可绑定ViewPager进行联动。

效果图如下

5b756e3800014b8f03560356.jpg


整个控件是基于HorizontalScrollView,把三角下标绘制在tab下方,控件的滑动可以分解成tab容器的滑动和三

角下标的滑动,关键在于计算好二者滑动的距离。

想要做到三角下标跟随手指滑动的效果,需要用到ViewPager的onPageScrolled接口:

mViewPager.addOnPageChangeListener(new OnPageChangeListener() {            @Override
            public void onPageSelected(int position) {                // 设置字体颜色高亮
                resetTextViewColor();
                highLightTextView(position);                // 回调
                if (onPageChangeListener != null) {
                    onPageChangeListener.onPageSelected(position);
                }
            }            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {                // 滚动
                scroll(position, positionOffset);                // 回调
                if (onPageChangeListener != null) {
                    onPageChangeListener.onPageScrolled(position, positionOffset, positionOffsetPixels);
                }

            }            @Override
            public void onPageScrollStateChanged(int state) {                // 回调
                if (onPageChangeListener != null) {
                    onPageChangeListener.onPageScrollStateChanged(state);
                }

            }
        });

其中,onPageScrolled的三个参数,重点介绍前两个:

position:如果从0向1滑动,position就是0;

positionOffset:是介于0和1之间的float型参数,如果从0向1滑动,指的是已滑的比列;

下面看看滑动过程的核心函数scroll:

 public void scroll(int position, float positionOffset) {        int tabWidth = mItemsLayout.getChildAt(position).getWidth();
        mTranslationX = (int) ((position + positionOffset) * tabWidth);        // 容器滚动,当移动到倒数最后一个的时候,开始滚动
        if (positionOffset > 0 && position >= (VISIBLE_TAB_COUNT - START_SCROLL) && mTotalItemsCount > VISIBLE_TAB_COUNT) {            //注意这里是整体滑动,使得tabs跟指示器保持相对静止
            this.scrollTo((position - (VISIBLE_TAB_COUNT - START_SCROLL)) * tabWidth + (int) (tabWidth * positionOffset), 0);
        }
        invalidate();
    }

mTranslationX :三角下标滑动的距离。

这里的滑动分为两部分:tab容器的滑动和三角下标的滑动。

这里定义,每个页面可见4个按钮,当选中到倒数第二个按钮时,tab容器开始滑动,即当position >=

(VISIBLE_TAB_COUNT - START_SCROLL) 时,容器开始滑动。此时整个容器会先整体滑动(包括三角下标,三角下标和tab保持相对静止),接着

开始invalidate(),调用绘制三角下标,绘制过程如下:

@Override
    protected void dispatchDraw(Canvas canvas) {
        canvas.save();        // 平移到正确的位置
        canvas.translate(mInitTranslationX + mTranslationX, this.mInitTranslationY);//修正tabs的平移量
        canvas.drawBitmap(this.mSlideIcon, 0, 0, null);
        canvas.restore();        super.dispatchDraw(canvas);
    }

这里用的是dispatchDraw,关于dispatchDraw和onDraw的区别,这里再提一下:

绘制View本身的内容,通过调用View.onDraw(canvas)函数实现

绘制自己的孩子通过dispatchDraw(canvas)实现

ViewGroup容器组件的绘制,当它没有背景时直接调用的是dispatchDraw()方法, 而绕过了draw()方法,当它有

背景的时候就调用draw()方法,而draw()方法里包含了dispatchDraw()方法的调用。因此要在ViewGroup上绘

制东西的时候往往重写的是dispatchDraw()方法而不是onDraw()方法。

回到绘制的过程,绘制这里用的是移动画布,再绘制,其实大可以直接绘制,即

@Override
    protected void dispatchDraw(Canvas canvas) {        
        canvas.drawBitmap(this.mSlideIcon, mInitTranslationX + mTranslationX, this.mInitTranslationY, null);        super.dispatchDraw(canvas);
    }

最后说下我在此过程中踩得坑。

首先最开始我并没有意识到可以直接在HorizontalScrollView绘制三角下标,所以我最开始是继承LinearLayout写的,三角下标在一个独立的LinearLayout里,结构如下:

5b756e3800011c4304420125.jpg

在处理容器的滑动时,我并不是整体滑动,而是让HorizontalScrollView滑动,即在scroll函数中:

 this.scrollTo((position - (VISIBLE_TAB_COUNT - START_SCROLL)) * tabWidth + (int) (tabWidth * positionOffset), 0);

变成了

 HorizontalScrollView对象.scrollTo((position - (VISIBLE_TAB_COUNT - START_SCROLL)) * tabWidth + (int) (tabWidth * positionOffset), 0);

这样的后果是,tab容器和三角下标没有保持相对静止,容器先向一方滑动了一部分,三角下标又向另一方滑了

一部分,导致出现三角下标越滑越多的情形。

原文链接:http://www.apkbus.com/blog-873057-77691.html

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消