RecyclerView fast scroll thumb height too small for large data set

I am using the default RecyclerView fast scroll and I followed this guide to support it.

Now, the problem is that the thumb resizes its height as per the size of the data set. For large items like 100 and above, the thumb becomes very small and almost becomes difficult to respond to dragging.

Please is there any way I can set minimum height for the fast scroll thumb.


This is only a partial answer; I'm missing (at least) one piece of the puzzle, but hopefully someone else can figure it out.

Once you've added the necessary attributes to your <RecyclerView> tag (as mentioned in the answer linked in OP's question), the sizing/positioning of the scrollbar thumb is controlled by three methods inside LinearLayoutManager :

  • int computeVerticalScrollRange() : The size of the scrollbar's track.

  • int computeVerticalScrollExtent() : The size of the scrollbar's thumb.

  • int computeVerticalScrollOffset() : The distance between the top of the scrollbar's track and the top of the scrollbar's thumb.

  • The units for these methods is arbitrary; you can use anything you'd like as long as all three methods share the same units. By default, LinearLayoutManager will use one of two sets of units:

  • mSmoothScrollbarEnabled == true : Use units based on the pixel sizes of the visible items in the RecyclerView .

  • mSmoothScrollbarEnabled == false : Use units based on the positions of the visible items in the RecyclerView 's adapter.

  • To control the size of the scrollbar's thumb yourself, you'll have to override these methods... but here's the piece I'm missing: In all of my experimentation, computeVerticalScrollExtent() is never called by the system . That said, we can still show some progress here.

    First, I've created a simple adapter that shows 500 CardView s with the item's position inside. I've enabled fast scrolling with some really simple (but ugly) drawables. Here's what the scrollbar looks like with just a default LinearLayoutManager implementation:

    在这里输入图像描述

    As you've found, with 500 (small) items, the scrollbar thumb is really small and quite hard to tap on. We can make the scrollbar dramatically larger by overriding computeVerticalScrollRange() to just return a fixed constant... I picked 5000 essentially at random just to show the major change:

    在这里输入图像描述

    Of course, now the scrollbar doesn't work like you'd expect; scrolling the list by dragging on it as normal moves the thumb much more than it should, and fast scrolling the list by dragging on the thumb moves the list much less than it should.

    On my device, with the randomly-chosen range of 5000 , overriding computeVerticalScrollOffset() as follows makes the scrollbar thumb move perfectly as I scroll the list by dragging on it:

    @Override
    public int computeVerticalScrollRange(RecyclerView.State state) {
        return 5000;
    }
    
    @Override
    public int computeVerticalScrollOffset(RecyclerView.State state) {
        return (int) (super.computeVerticalScrollOffset(state) / 23.5f);
    }
    

    However, this still doesn't fix the second issue: dragging on the thumb itself doesn't correctly scroll the list. As I mentioned above, it would seem like the appropriate thing to do here would be to override computeVerticalScrollExtent() , but the system never invokes this method. I've even overridden it to simply throw an exception, and my app never crashes.

    Hopefully this at least helps point people in the right direction for a full solution.

    PS: The implementations of computeVerticalScrollRange() and computeVerticalScrollOffset() I've included in this answer are intentionally simple (read: bogus). "Real" implementations would be much more complex; the default LinearLayoutManager implementations take into account device orientation, the first and last visible items in the list, the number of items off-screen in both directions, smooth scrolling, various layout flags, and so on.


    I solved this problem by copying the Fast Scroller classs from android.support.v7.widget.FastScroller

    Then I removed the fast scroll enabled from the xml and applied fastscroller using the below codes

    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));
    

    Inside the FastScroller Class I extended the defaultWidth

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

    Then I updated the code in this method

    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));
    ...    
    }
    

    This ensures that the minimum thumb height/width is 4 times the default width


    This is a known issue, opened in August 2017: https://issuetracker.google.com/issues/64729576

    Still waiting for recommendations on how to manage RecyclerView with fast scroll on large amounts of data. No reply from Google on that issue so far on recommendations :(

    The answer from Nabil is similar to a workaround mentioned in the issue. Nabil's answer copies the FastScroller class and modifies it to ensure a minimum thumb size, and the workaround in the issue extends FastScroller (but it has to stay in the android.support.v7.widget package) to ensure the minimum thumb size.

    链接地址: http://www.djcxy.com/p/40980.html

    上一篇: 通过ssh远程调试.net core 2.0控制台应用程序

    下一篇: RecyclerView快速滚动拇指高度对于大型数据集来说太小