RecyclerView快速滚动拇指高度太小,不适合大型数据集

X09*_*X09 15 android android-recyclerview

我正在使用默认的RecyclerView快速滚动,我按照本指南来支持它.

现在,问题是拇指根据数据集的大小调整其高度.对于100以上的大件物品,拇指变得非常小,几乎难以对拖动作出反应.

请问有什么方法可以为快速滚动拇指设置最小高度.

Ben*_* P. 6

这只是部分答案;我(至少)缺少一块拼图,但希望其他人能解决它。

一旦您向标签添加了必要的属性<RecyclerView>(如OP问题中链接的答案中所述),滚动条拇指的大小/位置将由内部的三种方法控制LinearLayoutManager

  • int computeVerticalScrollRange():滚动条轨道的大小。

  • int computeVerticalScrollExtent():滚动条拇指的大小。

  • int computeVerticalScrollOffset():滚动条轨道顶部与滚动条拇指顶部之间的距离。

这些方法的单位是任意的;您可以使用任何您想要的东西,只要所有三种方法共享相同的单位即可。默认情况下,LinearLayoutManager将使用两组单位之一:

  • mSmoothScrollbarEnabled == true:使用基于 中可见项目的像素大小的单位RecyclerView

  • mSmoothScrollbarEnabled == falseRecyclerView:根据适配器中可见项目的位置使用单位。

要自己控制滚动条拇指的大小,您必须重写这些方法...但这是我缺少的部分:在我所有的实验中,computeVerticalScrollExtent()系统从未调用过。也就是说,我们仍然可以在这里展示一些进展。

首先,我创建了一个简单的适配器,它显示 500CardView秒以及内部项目的位置。我已经启用了一些非常简单(但丑陋)的可绘制对象的快速滚动。这是默认LinearLayoutManager实现的滚动条的样子:

在此输入图像描述

正如您所发现的,对于 500 个(小)项目,滚动条拇指非常小并且很难点击。computeVerticalScrollRange()我们可以通过覆盖仅返回一个固定常量来使滚动条显着变大......我5000基本上随机选择只是为了显示主要变化:

在此输入图像描述

当然,现在滚动条并不像您期望的那样工作;正常情况下通过拖动来滚动列表,拇指的移动量会比应有的多,而通过拖动拇指快速滚动列表的移动量会比应有的少。

在我的设备上,使用随机选择的范围5000,覆盖computeVerticalScrollOffset()如下使得滚动条拇指在我通过拖动滚动列表时完美移动:

@Override
public int computeVerticalScrollRange(RecyclerView.State state) {
    return 5000;
}

@Override
public int computeVerticalScrollOffset(RecyclerView.State state) {
    return (int) (super.computeVerticalScrollOffset(state) / 23.5f);
}
Run Code Online (Sandbox Code Playgroud)

但是,这仍然无法解决第二个问题:拖动拇指本身无法正确滚动列表。正如我上面提到的,这里似乎合适的做法是 override computeVerticalScrollExtent(),但系统从不调用此方法。我什至重写了它以简单地抛出异常,并且我的应用程序永远不会崩溃。

希望这至少有助于为人们指明完整解决方案的正确方向。

PS:我在这个答案中包含的实现是故意简单的(阅读:伪造的computeVerticalScrollRange())。computeVerticalScrollOffset()“真正的”实现会复杂得多;默认LinearLayoutManager实现会考虑设备方向、列表中的第一个和最后一个可见项目、两个方向上屏幕外的项目数、平滑滚动、各种布局标志等。


小智 6

我通过从 android.support.v7.widget.FastScroller 复制 FastScroller 类解决了这个问题

然后我从xml中删除了启用的快速滚动并使用以下代码应用了fastscroller:

StateListDrawable verticalThumbDrawable = (StateListDrawable) getResources().getDrawable(R.drawable.fastscroll_sunnah);
Drawable verticalTrackDrawable = getResources().getDrawable(R.drawable.fastscroll_line_drawable);
StateListDrawable horizontalThumbDrawable = (StateListDrawable)getResources().getDrawable(R.drawable.fastscroll_sunnah);
Drawable horizontalTrackDrawable = getResources().getDrawable(R.drawable.fastscroll_line_drawable);

Resources resources = getContext().getResources();
new FastScroller(recyclerView, verticalThumbDrawable, verticalTrackDrawable,
                horizontalThumbDrawable, horizontalTrackDrawable,
                resources.getDimensionPixelSize(R.dimen.fastscroll_default_thickness),
                resources.getDimensionPixelSize(R.dimen.fastscroll_minimum_range),
                resources.getDimensionPixelOffset(R.dimen.fastscroll_margin));
Run Code Online (Sandbox Code Playgroud)

在 FastScroller 类中,我扩展了 defaultWidth:

FastScroller(RecyclerView recyclerView, StateListDrawable verticalThumbDrawable,
        Drawable verticalTrackDrawable, StateListDrawable horizontalThumbDrawable,
        Drawable horizontalTrackDrawable, int defaultWidth, int scrollbarMinimumRange,
        int margin) {
    ...
    this.defaultWidth = defaultWidth;
    ...
Run Code Online (Sandbox Code Playgroud)

然后我更新了这个方法中的代码:

void updateScrollPosition(int offsetX, int offsetY) {
...
mVerticalThumbHeight = Math.max(defaultWidth * 4, Math.min(verticalVisibleLength,
                (verticalVisibleLength * verticalVisibleLength) / verticalContentLength));
...
...
mHorizontalThumbWidth = Math.max(defaultWidth * 4, Math.min(horizontalVisibleLength,
                (horizontalVisibleLength * horizontalVisibleLength) / horizontalContentLength));
...    
}
Run Code Online (Sandbox Code Playgroud)

这确保最小拇指高度/宽度是默认宽度的 4 倍。