ViewPager导航的一些想法

每当UE给一个他们认为完美的交互时候,我们第一想法是卧槽,这种交互好像我没见过,有没有开源的,好不好做。
关于ViewPager的导航,网上的自定义控件非常多,大部分能够满足我们的需求,而且每一个开源出来的控件都有非常多的自定义属性,尽量让使用者可以更加全面的控制样式。但是如果没有我们需要的样式呢?我们还是深入了解一下它的原理吧。

常用示例

以下为慕课网APP中的两个应用场景。
image
在这里插入图片描述

通过以上可以看到主要的有如下几点:

  1. 选中效果
  2. 滚动居中
  3. 辅助指示(下划线等)
  4. 滚动反馈(动态改变状态栏颜色)

原理解析

针对上面所说的特点进行分别说明,整体的实现方案非常多,但思想都是大同小异,这里我们选取HorizontalScrollView 嵌套LinearLayoutLinearLayout中添加TextView的方案来进行说明。
其中选中效果比较好理解,设置选中位置文本颜色、文本大小等等的变化。

ViewPager滑动监听

我们都知道ViewPager提供了addOnPageChangeListener方法可以用来监听滑动翻页。

mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
    @Override
    public void onPageScrolled(int position, float positionOffset, @Px int positionOffsetPixels) {
    }

    @Override
    public void onPageSelected(int position) {
    }

    @Override
    public void onPageScrollStateChanged(int state) {
    }
});

针对每个方法来具体说明下:

  1. onPageSelected 有一个参数position,我们使用的比较多,就是被选中的位置。

  2. onPageScrollStateChanged
    其中status有如下三个状态:

    • SCROLL_STATE_IDLE(静止状态)
    • SCROLL_STATE_DRAGGING(拖动状态,手指按下并滑动)
    • SCROLL_STATE_SETTLING(释放状态,手指按下并滑动后抬起手指惯性滑动的一段。)
  3. onPageScrolled
    onPageScrolled方法也是非常重要而且不太好理解的回调方法,而且有三个参数:

    • position 源码中的注释是Position index of the first page currently being displayed. 在滑动翻页的过程中,我们是可以看到左右两页,这里的position就是左页的位置。这里很重要,后面两个参数也是相对于该位置来说的。
    • positionOffsetPixels 滑动过程中左页的位移(单位像素)
    • positionOffset 滑动过程中左页的位移与最大位移的比例 [0~1)

通过以上说明,对回调的方法有了大致的了解,然后大家可以根据下图来进行体会下,这几个回调方法很重要,每个参数都要清晰地理解。

在这里插入图片描述

滚动居中

如下图所示,怎么在由云计算/大数据 --> 前端开发 翻页的时候,导航跟随居中呢?
在这里插入图片描述
分析:

  1. 翻页前云计算/大数据Tab居中;
  2. 翻页过程中跟随ViewPager滑动Tab动态滚动;
  3. 翻页后前端开发Tab居中。
    在这里插入图片描述
    由于从云计算/大数据 --> 前端开发 翻页,这里我们定义云计算/大数据为第一页Tab即firstPageTabView,前端开发为第二页Tab即secondPageTabView。
    很容易得到,firstPageTabView中间到控件左边的距离:firstPageTabView距离左边距离 + firstPageTabView的宽度一半。需要将firstPageTabView的中间滚动到整体控件的中间,那么滚动的距离就是:firstPageTabView中间到控件左边的距离 - 控件宽度的一半。滑动开始前需要向左滚动的距离为:
    在这里插入图片描述
    同理,滑动到第二个时:
    在这里插入图片描述
    由于
    在这里插入图片描述
    所以滑动到第二个时也可以表示为:
    在这里插入图片描述
    但这只是计算了选择状态下需要滚动的距离,那么怎么得到需要动态滚动的距离呢?视乎还差的很远,其实对比一下开始和结束的距离:
    在这里插入图片描述
    对比发现,结束比开始多了firstPageTabView.getWidth()firstPageTabView.getWidth() / 2变成了secondPageTabView.getWidth() / 2,之前我们在ViewPager滑动监听中提到一个重要的回调方法onPageScrolled,该方法中positionOffset就是滚动距离的比例。我们变换下来推导下滑动过程的偏移量。
    在这里插入图片描述

通过以上推导就得到了滑动过程的计算方法,当然滑动过程的技术方法还可以进一步的整理优化。
最终得到的滚动方法如下:

void scrollToSelectedTab(int firstPagePosition, float positionOffset) {
    int childCount = mSlidingTabStrip.getChildCount();
    if (childCount == 0) {
        return;
    }

    View firstPageTabView = mSlidingTabStrip.getChildAt(firstPagePosition);
    float offset = firstPageTabView.getWidth() * positionOffset;
    float scrollX = getPaddingLeft() + firstPageTabView.getLeft() + offset - getWidth() / 2;

    float left = 0;
    float right = 0;
    if (firstPagePosition < childCount - 1) { // Sliding the page.
        View secondPageTabView = mSlidingTabStrip.getChildAt(firstPagePosition + 1);
        left = firstPageTabView.getLeft() + positionOffset * (secondPageTabView.getLeft() - firstPageTabView.getLeft());
        right = firstPageTabView.getRight() + positionOffset * (secondPageTabView.getRight() - firstPageTabView.getRight());
    } else if (firstPagePosition == childCount - 1) { // After selected the last page.
        left = firstPageTabView.getLeft();
        right = firstPageTabView.getRight();
    }
    scrollX += (right - left) / 2;
    scrollTo((int) scrollX, 0);
}

源码及示例

github地址:SlidingTabLayout

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值