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

大家好,在前段时间我写过用ScrollView实现了自定义滚轮,但是在循环的效果不是特别好

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

用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()方法来获取的,我本来在

@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!!然后就只能通过其他方式来获取滚动的距离。
获取滚动的距离:

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就可以了么。没错。这个是可以。但是调用这个方法,在接下去的第二种情况下就出现问题了。

  2. 顶部的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到里面。

所以代码如下:

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 222,104评论 6 515
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,816评论 3 399
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 168,697评论 0 360
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,836评论 1 298
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,851评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,441评论 1 310
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,992评论 3 421
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,899评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,457评论 1 318
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,529评论 3 341
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,664评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,346评论 5 350
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 42,025评论 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,511评论 0 24
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,611评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 49,081评论 3 377
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,675评论 2 359

推荐阅读更多精彩内容