前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >项目需求讨论- 自定义滚轮(第二波新实现)

项目需求讨论- 自定义滚轮(第二波新实现)

作者头像
青蛙要fly
发布2018-08-29 14:58:36
1.1K0
发布2018-08-29 14:58:36
举报

大家好,在前段时间我写过用ScrollView实现了自定义滚轮,但是在循环的效果不是特别好。(这次文章底部附上了Demo。O(∩_∩)O~

项目需求讨论-自定义滚轮

用ScrollView 循环有什么问题呢。
  1. 因为我们是重复建立数据,比如数据是[A,B,C,D,E,F],你可以做成假循环,比如变为[A,B,C,D,E,F][A,B,C,D,E,F][A,B,C,D,E,F],变为三遍,但是变到上面一组后,因为要重新回到中间,所以你会发现闪动一下的感觉,因为比如冲第一组的A(position为0)到了第二组的A(position为6)。
  2. 而且如果你手指快速的滑动,不停的滚动,你就会滑到顶部的位置。因为我们的是ScrollView 最后选中哪一项,才让它滚动到中间相应的那一项。
  3. 那有些人可能会说,那我就不只弄这几组。我就多弄几组不就好了。别人快速滑动也滑不到顶部了。Too young Too Simple。比如我用11组。但是你会发现,你的界面加载直接很久很久,因为ScrollView内的控件都直接要初始化好,因为你设置了11组。等于有66个Item在加载完。就会让界面卡死在那里。所以体验就更差了。

最后感谢黑马飞马同学给的意见。

对啊。我们的RecyclerView 是只会加载界面当前显示的Item,然后不管数量再多,也只是在复用相同的View而已。这样我们上面的问题不就解决了。因为比如我们建立一千组一万组数据,我不需要考虑要重新滚回中间,问题1和2就解决了。问题3因为RecyclerView 的特性,也被解决了。是一个很理想的循环滚动的滚轮。

于是就使用RecycleViewer来进行相关的开发。正式起航。


原理分析

  1. 滚轮的高度和Item的高度 比如我们确定一个页面显示5项,item的布局高度为100dp,那滚轮高度就设定为500dp.
  2. 怎么确定RecyclerView 停止滚动 自定义ScrollerListener 继承RecyclerView.OnScrollListener,复写里面的 @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); switch (newState) { case RecyclerView.SCROLL_STATE_IDLE: ..... ..... ..... break; } }复制代码 当state变为了RecyclerView.SCROLL_STATE_IDLE就说明了RecyclerView已经停止了。

3.比如只划一部分,如何让它自动滚到相应的Item(重点)

方法还是一样,通过当前获取到的滚到的Y值,然后除以每项的Item的高度,就能知道当前顶部是处于第几项,然后求余数就知道了当前顶部那项有多少是显示的。在上文我们ScrollView 中,我们使用的是getScrollY()方法来获取的,我本来在

代码语言:javascript
复制
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
    super.onScrollStateChanged(recyclerView, newState);
    switch (newState) {

        case RecyclerView.SCROLL_STATE_IDLE:
            recyclerView.getScrollY();

            break;
    }
}复制代码

所以我在onScrollStateChanged方法中通过getScrollY()方法去获取,多么Easy,哈哈,结果这次是我Too young Too simple,获取到的值一直为0。WTF!!然后就只能通过其他方式来获取滚动的距离。 获取滚动的距离:

代码语言:javascript
复制
public int getScollYDistance(RecyclerView recyclerView) {
    LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
    int position = layoutManager.findFirstVisibleItemPosition();
    View firstVisiableChildView = layoutManager.findViewByPosition(position);
    int itemHeight = firstVisiableChildView.getHeight();
    return (position) * itemHeight - firstVisiableChildView.getTop();
}复制代码

我想这个大家应该看得懂吧。我画个图解释一下就可以了:

我来大致解释下:如上图所示,我们现在一个Item是100的高度,那我们现在滑到了第二个的20的位置,那是不是一共滑动了120的距离。因为我们当前获取到该手机界面上显示的第一个的position是1,说明position为0的已经被滑出去了。外加这个当前界面的显示的position为1的item有部分被滑出去,所以我们获取它的getTop值为-20,所以是不是正好是当前界面显示的第一个Item的position,乘以itemHeight,减去这个item 的getTop的值。(1 * 100 - (-20) = 120)

好的,我们已经解决了滚动距离的问题。那现在就是我们要让他滚动到一定距离,自动调整自己的位置,来正好显示某个Item项,而不会出现某个Item在界面上显示一半。


滚动后调整距离让RecyclerView 滚到特定的position位置:

我简单介绍,就只分二种情况来谈下(正好滑到一个标准的距离,让Item正好完全显示这种情况我就去除了):

  1. 顶部的Item有小于一半ItemHeight的距离滚到了屏幕的外面:

这时候很简单,大家说获取到第一个Item的Position值,然后调用RecyclerView.smoothScrollToPosition(Position),跳到这个positionItem就可以了么。没错。这个是可以。但是调用这个方法,在接下去的第二种情况下就出现问题了。

  1. 顶部的Item有大于一半ItemHeight的距离滚到了屏幕外面:

这时候大家也知道,应该是让当前的屏幕内获取到的first Item 滚动出界面,所以大家一想就说获取第一个Item的Position值,然后调用RecyclerView.smoothScrollToPosition(Position + 1)不就可以了么。。完美!!。但是结果是不会滚动,原来这个方法当我们的Position + 1已经出现在屏幕上了。不管是不是第一个,不管处于屏幕的哪个位置,这个RecyclerView就不会滚动。我忍不住又一句 WHF!!。那应该怎么处理呢。

RecyclerView.ScrollBy方法 其实很简单。我直接抛弃了RecyclerView.smoothScrollToPosition方法,我们看到了,其实我们是不是可以通过判断,第一个Item有没有滚出一半的ItemHeight的距离在外面。无非是二种情况(假设一个ItemHeight为100):

  1. 已经有80滚动在外面了。我就通过ScrollBy 再向上过给它滚动20到外面。
  2. 已经有20滚动在外面了。我就通过ScrollBy 再向下返回20到里面。

所以代码如下:

代码语言:javascript
复制
private void smoothMoveToPosition(int n, RecyclerView mRecyclerView, LinearLayoutManager mLinearLayoutManager) {
    int firstItem = mLinearLayoutManager.findFirstVisibleItemPosition();
    if (firstItem == n) {
        int top = mRecyclerView.getChildAt(n - firstItem + 1).getTop();
        mRecyclerView.smoothScrollBy(0, -(itemHeight - top));

    } else {
        int top = mRecyclerView.getChildAt(n - firstItem).getTop();
        mRecyclerView.smoothScrollBy(0, top);
    }
}复制代码

SO EASY..妈妈再也不用担心我的学习了。步步高打火机,哪里不会点哪里


附上DEMO

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017年07月12日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 用ScrollView 循环有什么问题呢。
  • 原理分析
  • 3.比如只划一部分,如何让它自动滚到相应的Item(重点)
  • 附上DEMO
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档