RecycleView横向滑轮轮实现

本文介绍如何在Android中实现RecycleView的横向滑动,并且添加滚轴效果。通过自定义View并设置setXOffset()方法,可以达到滚轴随手势滑动的效果。详细步骤包括配置attrs.xml,布局文件的设定,以及Activity的相关操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

RecycleView横向滑动,要求实现如下滑轮蓝条可以随着手势跟随RecycleView界面左右滑动,类似滚轴

在这里插入图片描述
1.自定义View,单独设置setxoffSet()可实现滚动

package com.wttech.gm.tranmg.view;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.ViewTreeObserver;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import com.wttech.gm.tranmg.R;

/**
 * @author LZY
 * @time 2020-04-15.
 */
public class BottomGlideScrollView extends View {
    private Paint mPaint;
    private Path mPath;
    private int mBgColor = 0xffEDEDED;
    private int mScrollCollor = 0xff4090FF;
    private float mScrollWidth = 20;//滚轮宽度
    private float mScrollPostion = 0;//滚轮距离左边间距
    private float inVisableWidth = 0;//RecycleView不可见宽度
    private LinearLayoutManager layoutManager;

    public static final String TAG = "BottomGlideScrollView";

    public BottomGlideScrollView(Context context) {
        this(context, null);
    }

    public BottomGlideScrollView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public BottomGlideScrollView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        if (attrs != null) {
            TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.BottomGlideScrollView);
            mScrollWidth = (int) ta.getDimension(R.styleable.BottomGlideScrollView_scrollWidth, 20);
            ta.recycle();
        }
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setStrokeCap(Paint.Cap.ROUND);
        mPaint.setStrokeJoin(Paint.Join.ROUND);
        mPaint.setStyle(Paint.Style.FILL);
        mPaint.setStrokeWidth(5);
        mPath = new Path();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        drawOrginBg(canvas);
        drawScrollBg(canvas);
    }

    private void drawOrginBg(Canvas c) {
        int width = getWidth();
        drawLayout(c, width, mBgColor, 0);
    }

    private void drawScrollBg(Canvas c) {
        drawLayout(c, mScrollWidth, mScrollCollor, mScrollPostion);
    }

    private void drawLayout(Canvas c, float width, int color, float xoffset) {
        mPath.reset();
        mPaint.setColor(color);
        int height = getHeight();
        float radius = height / 2.0f;
        if (xoffset + width > getWidth()) {
            xoffset = (float) getWidth() - width;
        }
        RectF rectLeft = new RectF(xoffset, 0, height + xoffset, height);
        mPath.arcTo(rectLeft, 90, 180, false);
        mPath.moveTo(radius + xoffset, 0);
        mPath.lineTo(width - radius + xoffset, 0);
        mPath.lineTo(width - radius + xoffset, height);
        mPath.lineTo(radius + xoffset, height);
        mPath.close();
        RectF rectRight = new RectF(width - radius * 2 + xoffset, 0, width + xoffset, height);
        mPath.arcTo(rectRight, 270, 180, true);
        c.drawPath(mPath, mPaint);
    }

    /**
     * 设置scroll距离左边间距
     *
     * @param xoffset
     */
    public void setxoffSet(float xoffset) {
        if (xoffset < 0) {
            xoffset = 0;
        }
        if (inVisableWidth > 0) {
            mScrollPostion = (xoffset / inVisableWidth) * (getWidth() - mScrollWidth);
        } else {
            mScrollPostion = 0.0f;
        }
        invalidate();
    }

    public void setPaintWidth(int visableWidth, int totalWidth) {
        inVisableWidth = totalWidth - visableWidth;
        if (inVisableWidth < 0) {
            inVisableWidth = 0;
        }
        float percent = (float) visableWidth / totalWidth;
        if (percent <= 0 || percent > 1) {
            percent = 1;
        }
        mScrollWidth = (getWidth() * percent);
    }

    /**
     * 与RecycleView绑定,获取rv滚动距离
     *
     * @param recyclerView
     * @return
     */
    public int getRvScrollDistance(RecyclerView recyclerView) {
        View firstVisibleItem = recyclerView.getChildAt(0);
        int firstItemPosition = layoutManager.findFirstVisibleItemPosition();
        int itemWidth = firstVisibleItem.getWidth();
        int firstItemRight = layoutManager.getDecoratedRight(firstVisibleItem);
        return (firstItemPosition + 1) * itemWidth - firstItemRight;
    }


    /**
     * 与RecycleView绑定,获取rv全部宽度
     * 并不是严格意义宽度
     *
     * @param recyclerView
     * @return
     */
    public int getRvTotalWidth(RecyclerView recyclerView) {
        int width = 0;
        View firstVisibleItem = recyclerView.getChildAt(0);
        if (firstVisibleItem == null) {
            return width;
        }
        int decoratedWidth = layoutManager.getDecoratedMeasuredWidth(firstVisibleItem);
        Log.i(TAG, "decoratedWidth:" + decoratedWidth + ",firstVisibleItem:" + firstVisibleItem.getWidth());
        int size = layoutManager.getItemCount();
        if (size > 0) {
            width = decoratedWidth * (size - 1) + firstVisibleItem.getWidth();
        }
        return width;
    }

    /**
     * 绑定联动Recycleview
     */
    public void bindRecycleView(RecyclerView recyclerView) {
        layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
        recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {

            @Override
            public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
                float scrollY = getRvScrollDistance(recyclerView);
                setPaintWidth(recyclerView.getWidth(), getRvTotalWidth(recyclerView));
                setxoffSet(scrollY);
                Log.i(TAG, "scrollY:" + scrollY + "---width:" + recyclerView.getWidth());
            }
        });
        //监听数据改变layout,更新显示条宽度
       recyclerView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
           @Override
           public void onGlobalLayout() {
               setPaintWidth(recyclerView.getWidth(), getRvTotalWidth(recyclerView));
           }
       });
    }
}

attrs.xml

    <declare-styleable name="BottomGlideScrollView">
        <attr name="scrollWidth" format="dimension|reference"/>
    </declare-styleable>

2.布局文件

 <com.custom.BottomGlideScrollView
                android:id="@+id/bottomGlideScrollView"               
                android:layout_width="@dimen/dp40"
                android:layout_height="@dimen/dp4"
                app:scrollWidth="@dimen/dp15"
                />

3.Activity

  LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getContext());
  linearLayoutManager.setOrientation(RecyclerView.HORIZONTAL);
  recycleview.setLayoutManager(linearLayoutManager);
  //将RecycleView与控件绑定
  bottomGlideScrollView.bindRecycleView(recycleview);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值