RecyclerView的fastScroll

作者: 有点健忘 | 来源:发表于2020-09-10 16:09 被阅读0次

    快速滑动条

    默认的效果就是不滚动的时候不显示,滚动以后出现。可以手动拖动滑块实现快速滑动。


    image.png

    app:fastScrollEnabled为true生效,这时候其他4个相关的Drawable缺一不可,否则异常

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/rv_main"
            app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            app:fastScrollEnabled="true"
            app:fastScrollVerticalThumbDrawable="@drawable/state_thumb_test"
            app:fastScrollVerticalTrackDrawable="@drawable/shape_track_bg"
            app:fastScrollHorizontalThumbDrawable="@drawable/state_thumb_test"
            app:fastScrollHorizontalTrackDrawable="@drawable/shape_track_bg"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/toolbar" />
    

    看下源码,里边init的时候有判断,4个drawable必须都有,否则抛出异常

            mEnableFastScroller = a.getBoolean(R.styleable.RecyclerView_fastScrollEnabled, false);
            if (mEnableFastScroller) {
                StateListDrawable verticalThumbDrawable = (StateListDrawable) a
                        .getDrawable(R.styleable.RecyclerView_fastScrollVerticalThumbDrawable);
                Drawable verticalTrackDrawable = a
                        .getDrawable(R.styleable.RecyclerView_fastScrollVerticalTrackDrawable);
                StateListDrawable horizontalThumbDrawable = (StateListDrawable) a
                        .getDrawable(R.styleable.RecyclerView_fastScrollHorizontalThumbDrawable);
                Drawable horizontalTrackDrawable = a
                        .getDrawable(R.styleable.RecyclerView_fastScrollHorizontalTrackDrawable);
                initFastScroller(verticalThumbDrawable, verticalTrackDrawable,
                        horizontalThumbDrawable, horizontalTrackDrawable);
            }
    
    //4个drawable都必须有,ThumbDrawable可以是state状态,比如press为true和false显示不同颜色的图
        void initFastScroller(StateListDrawable verticalThumbDrawable,
                Drawable verticalTrackDrawable, StateListDrawable horizontalThumbDrawable,
                Drawable horizontalTrackDrawable) {
            if (verticalThumbDrawable == null || verticalTrackDrawable == null
                    || horizontalThumbDrawable == null || horizontalTrackDrawable == null) {
                throw new IllegalArgumentException(
                        "Trying to set fast scroller without both required drawables."
                                + exceptionLabel());
            }
    
            Resources resources = getContext().getResources();
            new FastScroller(this, verticalThumbDrawable, verticalTrackDrawable,
                    horizontalThumbDrawable, horizontalTrackDrawable,
                    resources.getDimensionPixelSize(R.dimen.fastscroll_default_thickness),
                    resources.getDimensionPixelSize(R.dimen.fastscroll_minimum_range),
                    resources.getDimensionPixelOffset(R.dimen.fastscroll_margin));
        }
    

    下边只分析vertical滚动条, 水平方向也一样的道理
    TrackDrawable: 就是那个背景条,宽度就是drawable的宽【水平方向滚动那就是高了】,有个默认的最小值8dp.
    ThumbDrawable:就是那个可以拖动的滑块了
    如果这两个drawable的宽不一样,那么左边界就是大的那个来确定的,如下图,我TrackDrawable宽度是25dp,ThumbDrawablek宽度是40dp


    image.png

    固定高度的滑块

    系统自带的正常来说就可以的,可有人觉得数据太多的时候滑块的高度太小了,想要一个固定高度的滑块。
    系统的是没办法了,因为并没有对外提供可以修改的东西。
    那咋办了?
    看了下系统滑块就是一个ItemDecoration ,那我们把这个类复制下,完事稍微修改下滑块高度不就行了

    class FastScroller extends RecyclerView.ItemDecoration implements RecyclerView.OnItemTouchListener
    

    简单看下源码
    滑块的位置以及大小由下边2个变量决定的,所以搜一下这个两个值是在哪里赋值的就行了,然后改掉
    mVerticalThumbCenterY:滑块的中心位置
    mVerticalThumbHeight :滑块的高度


    image.png

    系统代码

            if (mNeedVerticalScrollbar) {
                float middleScreenPos = offsetY + verticalVisibleLength / 2.0f;
                mVerticalThumbCenterY =
                    (int) ((verticalVisibleLength * middleScreenPos) / verticalContentLength);
                mVerticalThumbHeight = Math.min(verticalVisibleLength,
                    (verticalVisibleLength * verticalVisibleLength) / verticalContentLength);
            }
    

    复制一下源码,改动下上边这个地方就可以了

                mVerticalThumbHeight=50;//固定高度
                mVerticalThumbCenterY=mVerticalThumbHeight/2+(verticalVisibleLength-mVerticalThumbHeight)*offsetY/(verticalContentLength-verticalVisibleLength);
    

    简单说下

    mVerticalThumbHeight/2 滑块中心点的起始位置,滑块高度的一半
    (verticalVisibleLength-mVerticalThumbHeight) 滑块可以移动的距离,很明显就是recyclerview的高度减去滑块的高度
    offsetY/(verticalContentLength-verticalVisibleLength) 当前的偏移量除以总的可以移动的距离,也就是比例了,从0到1,不要直接用额,要不都是int一除成0了,乘以1f 或者再前边先乘以总量

    用的时候很简单,代码里直接new一个对象即可,里边会自动add进去的

                FastScroller2(
                    rv, verticalThumbDrawable, verticalTrackDrawable,
                    verticalThumbDrawable, verticalTrackDrawable,
                    resources.getDimensionPixelSize(R.dimen.fastscroll_default_thickness),
                    resources.getDimensionPixelSize(R.dimen.fastscroll_minimum_range),
                    resources.getDimensionPixelOffset(R.dimen.fastscroll_margin)
                )
    

    跟随滑块的悬浮窗

    这个更简单了,滑块背景的位置刚才分析过了,我们再新加个view在容器里,位置marginEnd滑块宽度就行了,然后监听滚动状态,让它显示并translateY就行了.
    算出的progress就是滚动的范围,从0到1,和上边固定滑块逻辑一样的。
    然后你看下悬浮窗可以滚动的范围,乘以这个因子就行了.

                addOnScrollListener(object :RecyclerView.OnScrollListener(){
    
                    override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
    
                    }
    
                    override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
                        val range=recyclerView.computeVerticalScrollRange()
                        val offset=recyclerView.computeVerticalScrollOffset()
                        val progress=offset*1.0f/(range-recyclerView.height)
                    }
                })
    

    相关文章

      网友评论

        本文标题:RecyclerView的fastScroll

        本文链接:https://www.haomeiwen.com/subject/pnepektx.html