You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何控制GridLayoutManager布局下RecyclerView的滚动速度并限制快速滚动加载未加载图片?

嘿,我之前也碰到过GridLayoutManager搭配RecyclerView时滚动过快的问题,结合你的场景(5000+本地图片、担心快速滚动触发大量加载),给你几个亲测有效的解决方案:

一、减慢手动滑动的滚动速度(Fling速度)

GridLayoutManager本身没有直接调整滚动速度的API,但我们可以通过自定义它的Scroller来降低fling(快速滑动后的惯性滚动)速度。创建一个自定义的GridLayoutManager,重写createScroller方法替换成自定义的OverScroller,通过系数降低速度:

public class SlowGridLayoutManager extends GridLayoutManager {
    // 系数越小,滚动越慢,可根据需求调整(比如0.5f-0.8f)
    private static final float SCROLL_SPEED_FACTOR = 0.6f;

    public SlowGridLayoutManager(Context context, int spanCount) {
        super(context, spanCount);
    }

    public SlowGridLayoutManager(Context context, int spanCount, int orientation, boolean reverseLayout) {
        super(context, spanCount, orientation, reverseLayout);
    }

    @Override
    public RecyclerView.Scroller createScroller(Context context) {
        return new SlowScroller(context);
    }

    private class SlowScroller extends OverScroller {
        public SlowScroller(Context context) {
            super(context);
        }

        @Override
        public void fling(int startX, int startY, int velocityX, int velocityY, int minX, int maxX, int minY, int maxY, int overX, int overY) {
            // 给滑动速度乘以阻尼系数,降低惯性滚动的速度
            super.fling(startX, startY, 
                (int)(velocityX * SCROLL_SPEED_FACTOR), 
                (int)(velocityY * SCROLL_SPEED_FACTOR), 
                minX, maxX, minY, maxY, overX, overY);
        }
    }
}

之后把你原来的GridLayoutManager替换成这个SlowGridLayoutManager,就能明显减慢手动快速滑动后的惯性滚动速度。

二、控制smoothScrollToPosition的滚动速度

针对smoothScrollToPosition的滚动速度,我们可以在自定义的GridLayoutManager里重写该方法,使用自定义的LinearSmoothScroller来控制速度:

在刚才的SlowGridLayoutManager中添加以下代码:

@Override
public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) {
    LinearSmoothScroller smoothScroller = new LinearSmoothScroller(recyclerView.getContext()) {
        @Override
        protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) {
            // 数值越大,滚动越慢,比如20f(可根据需求调整)
            // 这个值的单位是"毫秒/每像素",所以值越大,滚动相同距离耗时越久
            return 20f / displayMetrics.densityDpi;
        }

        @Override
        protected int getVerticalSnapPreference() {
            // 滚动到目标位置的顶部对齐,也可以用SNAP_TO_CENTER居中对齐
            return SNAP_TO_START;
        }
    };

    smoothScroller.setTargetPosition(position);
    startSmoothScroll(smoothScroller);
}

这样调用recyclerView.smoothScrollToPosition(position)时,就会按照你设定的速度平滑滚动,完全适配GridLayoutManager。

三、避免快速滚动时的图片加载压力

你的核心痛点之一是快速滚动时触发大量Glide加载,其实可以通过RecyclerView的滚动监听,在滚动时暂停Glide请求,停止滚动后再恢复,同时优化Glide的加载配置:

1. 添加滚动监听控制Glide加载

recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
    @Override
    public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
        super.onScrollStateChanged(recyclerView, newState);
        Context context = recyclerView.getContext();
        if (newState == RecyclerView.SCROLL_STATE_IDLE) {
            // 滚动停止,恢复Glide加载
            Glide.with(context).resumeRequests();
        } else {
            // 正在滚动,暂停Glide所有请求
            Glide.with(context).pauseRequests();
        }
    }
});

2. 优化Glide加载配置

在你的onBindViewHolder里,添加占位图并优化裁剪策略,减少绘制压力:

@Override 
public void onBindViewHolder(@NonNull MyViewHolder holder, int position) { 
    GlideApp.with(context) 
        .load(arrayList.get(position).getUri()) 
        .placeholder(R.drawable.placeholder_image) // 添加占位图,滚动时显示
        .error(R.drawable.error_image) // 加载失败时的占位图
        .apply(RequestOptions.overrideOf(180,180).centerCrop()) // 固定尺寸+裁剪,减少绘制开销
        .diskCacheStrategy(DiskCacheStrategy.RESOURCE) 
        .into(holder.img); 
}

这样快速滚动时,RecyclerView只会显示占位图,不会触发真实图片的加载,只有当滚动停止后,Glide才会开始加载可见区域的图片,彻底解决前台加载压力的问题。


内容的提问来源于stack exchange,提问作者Anirudhdhsinh Jadeja

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 20:12:44