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

如何修复RecyclerView的StaggeredGridLayoutManager滚动时内容分散错位问题

我最近碰到个需求:要从API拉取远程图片,然后做成Pinterest那种瀑布流网格展示。一开始用普通GridView倒是能正常显示图片,但瀑布流的错落感完全做不出来。查了好多资料试了各种方法,终于搞定了,把方案整理出来给大家参考:

实现Pinterest风格瀑布流展示API图片的方案

核心技术选型

  • 图片加载与缓存:选用Fresco,它对远程图片的加载、缓存逻辑处理得很成熟,省了不少自己造轮子的功夫
  • 瀑布流布局容器:放弃无法实现错落布局的GridView,改用搭配StaggeredGridLayoutManager的RecyclerView,这是实现瀑布流的核心

具体实现步骤

1. 自定义条目布局

每个图片条目用Fresco提供的SimpleDraweeView来承载,写一个极简的item布局文件item_masonry.xml:

<?xml version="1.0" encoding="utf-8"?>
<com.facebook.drawee.view.SimpleDraweeView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:fresco="http://schemas.android.com/apk/res-auto"
    android:id="@+id/simple_drawee_view"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    fresco:placeholderImage="@drawable/img_placeholder"
    fresco:failureImage="@drawable/img_load_fail"
    fresco:viewAspectRatio="1.0"/>

2. 自定义RecyclerView适配器(MasonryAdapter)

写一个继承自RecyclerView.Adapter的自定义适配器,把API返回的图片URL和SimpleDraweeView绑定:

public class MasonryAdapter extends RecyclerView.Adapter<MasonryAdapter.MasonryViewHolder> {
    private List<String> imageUrlList;

    public MasonryAdapter(List<String> imageUrlList) {
        this.imageUrlList = imageUrlList;
    }

    @NonNull
    @Override
    public MasonryViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View itemView = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.item_masonry, parent, false);
        return new MasonryViewHolder(itemView);
    }

    @Override
    public void onBindViewHolder(@NonNull MasonryViewHolder holder, int position) {
        Uri imageUri = Uri.parse(imageUrlList.get(position));
        holder.draweeView.setImageURI(imageUri);
        
        // 随机设置item高度,模拟瀑布流错落感
        ViewGroup.LayoutParams params = holder.draweeView.getLayoutParams();
        params.height = getRandomItemHeight();
        holder.draweeView.setLayoutParams(params);
    }

    @Override
    public int getItemCount() {
        return imageUrlList.size();
    }

    static class MasonryViewHolder extends RecyclerView.ViewHolder {
        SimpleDraweeView draweeView;

        public MasonryViewHolder(@NonNull View itemView) {
            super(itemView);
            draweeView = itemView.findViewById(R.id.simple_drawee_view);
        }
    }

    private int getRandomItemHeight() {
        // 生成200-500之间的随机高度
        return new Random().nextInt(300) + 200;
    }
}

3. 配置RecyclerView与StaggeredGridLayoutManager

在Activity/Fragment中初始化RecyclerView,设置布局管理器和适配器:

RecyclerView masonryRecycler = findViewById(R.id.rv_masonry);
// 设置2列垂直瀑布流布局
StaggeredGridLayoutManager layoutManager = new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL);
// 解决滑动时item位置错乱的问题
layoutManager.setGapStrategy(StaggeredGridLayoutManager.GAP_HANDLING_NONE);
masonryRecycler.setLayoutManager(layoutManager);

// 假设已经从API获取到图片URL列表imageList
MasonryAdapter adapter = new MasonryAdapter(imageList);
masonryRecycler.setAdapter(adapter);

补充提示

  • 如果想要根据图片实际宽高比例设置item高度(而非随机),可以通过Fresco的图片加载监听获取宽高信息,再计算对应高度,这样瀑布流会更贴合图片本身比例
  • 务必记得在自定义Application中初始化Fresco:
public class MyApp extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        Fresco.initialize(this);
    }
}

内容的提问来源于stack exchange,提问作者Sukanta Paul

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 09:36:01