Android RecyclerView 实现瀑布流

2023-10-26

Android RecyclerView 使用大全 - 基础使用,item 动画,下拉刷新等

瀑布流也是个常用的显示控件了,但是在使用时经常遇到一些问题,比如滑动回顶部后出现空隙、item在滑动时乱跳等问题。

下面就来说说我怎么实现的瀑布流,并且怎么处理上面所说的这些问题的。

我使用了原生控件RecyclerView+StaggeredGridLayoutManager来实现的瀑布流,没有用第三方开源框架。下面以2列的瀑布流为例子开始讲解。

因为使用了StaggeredGridLayoutManager实现瀑布流,但是在设置后发现图片在滑动加载过程中高度会发生变化,在网上搜索了很多资料后,总结解决办法是在onBindViewHolder中绑定View时,给ImageView设置宽高,就能解决这个问题。

先看一下最终实现效果:

img

正常显示的瀑布流.gif

提前说明下,我使用的是Glide3,读者们可以自行修改为Glide4。

1.实现瀑布流

先说说实现思路:

  • 写布局文件,分别有2个布局文件,Activity的布局文件和Adapter的布局文件
  • 写适配器,瀑布流的适配器里需要设置ImageView的宽高。
  • 写RecyclerView,给RecyclerView设置StaggeredGridLayoutManager并设置适配器。
  • 添加数据测试效果,根据效果反馈进行修改

第一步:写布局文件

Activity的布局文件只有一个RecyclerView就不贴了,贴一下Adapter的布局文件:

adapter_item_card.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/card"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginTop="10dp"
    android:background="@android:color/holo_green_dark"
    android:orientation="vertical">

    <ImageView
        android:id="@+id/card_image"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        tools:src="@mipmap/ic_launcher" />

    <TextView
        android:id="@+id/card_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:layout_marginTop="8dp"
        android:layout_marginBottom="2dp"
        tools:text="hello" />
</LinearLayout>

第二步:写适配器

适配器中包含数据Card的集合,Card类包含如下几个属性:

    private String title;
    private String img_url;
    private int width;
    private int height;

在适配器中主要就是将数据绑定到view上,最关键的步骤是根据图片的宽高算出图片的宽高比,然后根据宽高比选择正方形显示,还是长方形显示,最后通过setLayoutParams方法来设置图片的宽高。

思路如下:

  • 计算图片宽度
  • 根据图片宽高比,确定图片使用正方形或是4比3的长方形显示
  • 使用setLayoutParams方法设置图片宽高
  • 使用Glide加载图片并用override重写图片宽高

适配器核心代码如下:

private final double STANDARD_SCALE = 1.1; //当图片宽高比例大于STANDARD_SCALE时,采用3:4比例,小于时,则采用1:1比例
private final float SCALE = 4 * 1.0f / 3;       //图片缩放比例
private List<Card> cards = new ArrayList<>();

@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
    Card card = mCards.get(position);
    setCardView(holder, card);
}

private void setCardView(ViewHolder holder, Card card) {
    //计算图片宽高
    LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) holder.image.getLayoutParams();
    //2列的瀑布流,屏幕宽度减去两列间的间距space所的值再除以2,计算出单列的imageview的宽度,space的值在RecyclerView初始化时传入
    float itemWidth = (ScreenUtil.getScreenWidth(context) - space) / 2;
    layoutParams.width = (int) itemWidth;

    float width = card.getWidth();
    float height = card.getHeight();
    float scale = height / width;
    if (scale > STANDARD_SCALE) {
        //采用3:4显示
        layoutParams.height = (int) (itemWidth * SCALE);
    } else {
        //采用1:1显示
        layoutParams.height = (int) itemWidth;
    }
    holder.image.setLayoutParams(layoutParams);
    Glide.with(context).load(card.getImg_url()).asBitmap().placeholder(R.mipmap.ic_launcher)
            .diskCacheStrategy(DiskCacheStrategy.RESULT).centerCrop().into(holder.image);
    holder.title.setText(card.getTitle());
}

写好适配器后,就可以在MAinActivity中初始化RecyclerView和适配器了,代码如下:

        int space = 20;
        StaggeredGridLayoutManager layoutManager = new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL);
//        layoutManager.setGapStrategy(StaggeredGridLayoutManager.GAP_HANDLING_NONE);   //设置后瀑布流不显示了
        mRecyclerView.setLayoutManager(layoutManager);
        mRecyclerView.setItemAnimator(null);
        mRecyclerView.addItemDecoration(new StaggeredItemDecoration(space));//单位px
        mAdapter = new StaggeredGridAdapter(space);
        mAdapter.setCards(mCards);
        mRecyclerView.setAdapter(mAdapter);

在网上看到使用StaggeredGridLayoutManager的setGapStrategy(StaggeredGridLayoutManager.GAP_HANDLING_NONE)设置来处理瀑布流滑动到顶部空白的问题,结果发现添加这句代码后,整个瀑布流都不显示了,所以不能这样处理。

在上面的代码中我设置了space值,space是指两列卡片之间的距离,根据需求设置,这里space用在了2个地方分别是:

mRecyclerView.addItemDecoration(new StaggeredItemDecoration(space));
mAdapter = new StaggeredGridAdapter(space);

前者用于设置两列瀑布流之间的距离,后者是用来计算单列图片的宽度。StaggeredItemDecoration类的代码在此

代码写好后,来看看瀑布流效果。

img

好像有点奇怪的地方,在滑动过程中前面图片1、2、3的大小发生了变化。我当时也是很疑惑,在网上搜索图片大小改变的问题原因也没有找到,好像与RecyclerView的图片缓存机制有关,有知道的胖友可以告知一下。

最后通过在Glide加载图片时添加override设置图片宽高解决了,关于override设置图片可以看看这篇文章《Glide的override方法和View的setLayoutParams方法设置图片宽高对比》

Glide.with(context).load(card.getImg_url()).asBitmap().placeholder(R.mipmap.ic_launcher)
                .diskCacheStrategy(DiskCacheStrategy.RESULT).override(layoutParams.width, layoutParams.height).centerCrop().into(holder.image);

解决后的效果如下,可以看到在滑动过程中,图片大小没有再变化:

img

正常显示的瀑布流.gif

2. 瀑布流顶部出现空隙、item乱跳等问题

照上面的处理已经能解决顶部出现空隙、item乱跳的问题,但是建议在瀑布流更新时采用notifyItemRangeInserted()方法更新,可以避免一些不必要的问题。

if (FIRST_PAGE_LAST_ID.equals(lastId)) {
    mAdapter.notifyDataSetChanged();//第一页更新
} else {
    mAdapter.notifyItemRangeInserted(startPosition, count);//第一页以外使用notifyItemRangeInserted()更新
}

如果对你有帮助的话,点赞、评论、赞赏都是对我的鼓励,也是支持我写下去的动力,谢谢!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android RecyclerView 实现瀑布流 的相关文章

  • 我们如何从 Android 通知中提取 bigpicturestyle 图像?

    我有一个通知侦听器服务 可以读取来自其他应用程序的通知 经用户许可 并提取所有数据 能够访问除通知展开视图中显示的图像之外的所有内容 我也在阅读 EXTRA PICTURE 意图值 if extras containsKey Notific
  • 如何使用 kotlin Android 从 Url 读取 JSON?

    我正在使用 kotlin 来开发应用程序 现在我想从服务器获取 JSON 数据 在java中 我实现了Asyntask以及Rxjava来从Url读取JSON 我也在谷歌搜索 但我无法获得满足我的要求的正确详细信息 如何使用 kotlin 从
  • 使用 PutDataMapRequest 后,Wearable.DataApi.getDataItem() 的 Uri 是什么?

    我正在测试可穿戴数据层 API如中所述安卓教程 http developer android com training wearables data layer index html 有一个基于底层 APIDataItem http dev
  • 在 Android 中从麦克风录制 wav 文件 - 问题

    我需要能够使用 Android 中的麦克风创建 WAV 文件 目前 我遇到了很多麻烦 到目前为止 这就是我的情况 我正在使用 micDroid 项目代码的一部分来记录 read thread int sampleRate 44100 int
  • Android模拟器中的互联网连接始终显示连接状态

    我尝试了多种方法来检查我的 Android 模拟器中的互联网连接 ConnectivityManager conMgr ConnectivityManager getSystemService Context CONNECTIVITY SE
  • 视图无法解析为类型

    这里的视图似乎有什么问题 我该如何解决它 错误 视图无法解析为类型 public void onItemClick AdapterView
  • 如何解决:无法解析:com.mapbox.mapboxsdk:mapbox-android-sdk:9.5.0

    我在Android studio中尝试使用mapbox时遇到这个问题无法解析 com mapbox mapboxsdk mapbox android sdk 9 5 0 问题是什么 我的 build gradle 依赖项 dependenc
  • 多种语言的多种字体

    我最近在开发应用程序时遇到了一种情况 我必须在文本视图中显示不同的语言 目前我正在展示一些使用字体 字体像这样 Typeface tf Typeface createFromAsset this getAssets DroidHindi t
  • 如何调试“com.android.okhttp”

    在android kitkat中 URLConnection的实现已经被OkHttp取代 如何调试呢 OkHttp 位于此目录中 external okhttp android main java com squareup okhttp 当
  • 如何向 Android Studio 中的现有项目添加新活动?

    在 Eclipse 中 您只需单击 新建 按钮并选择 Android 活动即可添加新活动 但 Android Studio 有点不同 我无法找到如何向项目添加新活动 要添加一个Activity使用 Android Studio 此步骤与添加
  • TextView 宽度匹配drawableTop 宽度

    有什么办法可以使TextView width匹配复合可绘制宽度 XML 例如对于 xml 代码
  • 警报对话框中的 Webview 不显示内容

    我正在开发一个 Android 应用程序 我需要在网络视图和警报对话框上显示一个网站 该站点显示在网络视图中 但不显示在警报对话框中 到目前为止 这是我的代码 WebView WebView myWebView WebView v find
  • 带有 backstack Resume 的嵌套片段

    在我的应用程序中有几个fragments in an activity我正在维护一个backStack对于这些fragment 一切都很好 但其中有一个嵌套的片段 当我把它放入backStack然后再次按后退按钮恢复 该片段看起来与先前的内
  • react-native android fontFamily 不生效

    问题一 我在index android js的欢迎样式中添加了fontFamily 但没有效果 fontFamily 真的可以在 Android 上使用吗 欢迎 字体大小 20 fontFamily roboto thin 文本对齐 居中
  • 在android中从SD卡上传图像到facebook

    我无法从 SD 卡上传 Facebook 上的图像 我使用了下面的代码 但它没有给我错误 但同时它没有上传图像 byte data null try FileInputStream fis new FileInputStream filep
  • 如何使用 isInEditMode() 在编辑器中查看自定义视图的布局

    我必须编辑一个具有自定义视图的软件 当我尝试编辑布局 xml 时 Eclipse 告诉我 在自定义视图中使用 View isInEditMode 可以在显示时跳过代码 在日食中 但我不知道how and where我必须使用isInEdit
  • 如何模拟ARM处理器运行环境并加载Linux内核模块?

    我尝试加载我的vmlinux into gdb并使用 ARM 内核模拟器 但我不明白为什么我会得到Undefined target command sim 这是外壳输出 arm eabi gdb vmlinux GNU gdb GDB 7
  • Android View Canvas onDraw 未执行

    我目前正在开发一个自定义视图 它在画布上绘制一些图块 这些图块是从多个文件加载的 并将在需要时加载 它们将由 AsyncTask 加载 如果它们已经加载 它们只会被绘制在画布上 这工作正常 如果加载了这些图片 AsyncTask 就会触发v
  • View.post(),以及当Runnables被执行时

    我最初的问题是需要知道我的根的高度和宽度View这样我就可以进行程序化的布局更改 就我的目的而言 我不一定需要在onCreate 对于我来说 以编程方式添加我的孩子就足够了View根布局完成后 因此我很乐意使用onWindowFocusCh
  • Keystore getEntry 在 Android 9 上返回 NULL

    c我已对存储在 Android 密钥库中的登录密码进行了加密和解密 在 Android 9 上 我观察到应用程序在尝试解密密码时崩溃 我无法重现它 但拥有 Pixel 3 的用户是崩溃的设备之一 下面是我如何从密钥库解密密码 private

随机推荐

  • tp5如何跨数据库查询

    gt 当然前提是 这两个的数据库都在同一个服务器上才可以的 如果没有在同一个服务器上 gt 解决办法 mysql设置一下权限 a 可以对b进行select的操作权限 tp5使用原生查询 代码如下 admin Db query SELECT
  • orangepi5使用sata ssd启动系统

    使用sata ssd启动香橙派官方的Ubuntu系统 以Orangepi5 1 1 0 ubuntu jammy server linux5 10 110为例 因为烧录系统到外接的ssd需要另一个系统辅助所以我们还要烧录一个带桌面的系统到T
  • 解决 LINK : fatal error LNK1104: 无法打开文件“freeglutd.lib”问题

    最近跑程序 发现总有这样的错误 如下图 开始我以为是缺少了freeglutd lib这个文件 之后才发现压根没有这个文件 于是找到了解决办法 鼠标右键单击项目 选择属性 出现如下图 找到C C 预处理器 点开预处理器定义 点编辑 添加 ND
  • libevent源码学习(0):libevent库安装与简单使用

    目录 1 下载并解压libevent库 2 安装libevent库 3 简单使用libevent库 1 下载并解压libevent库 这里下载的是libevent 2 0 21 stable版本的 使用wget命令如下所示 下载地址可通过h
  • .git文件夹_Git入门细致讲解

    什么是 git 分布式的版本管理与协作系统 安装 Git 下载安装就不详说了 安装之后 右键会出现 Git bush here 在当前文件夹打开 bash 是一个小型的 linux shell 可以在上面进行关于 git 的操作 他自带 m
  • 妙用mov edi,edi和5个nop实现inline hook

    妙用mov edi edi和5个nop实现inline hook 2008年2月22日 分类 其它技术 标签 inline hook nop 这方法MJ很早时就说过了 简单重复下 大家应该发现大部分API的第一条指令都是mov edi ed
  • MySQL 5.7版本简介

    MySQL的优势 MySQL的主要优势如下 1 速度 运行速度快 2 价格 MySQL对多数个人来说是免费的 3 容易使用 与其他大型数据库的设置和管理相比 其复杂程度较低 易于学习 4 可移植性 能够工作在众多不同的系统平台上 例如 Wi
  • MySQL—SQL优化详解(上)

    作者 小刘在C站 个人主页 小刘主页 努力不一定有回报 但一定会有收获加油 一起努力 共赴美好人生 学习两年总结出的运维经验 以及思科模拟器全套网络实验教程 专栏 云计算技术 小刘私信可以随便问 只要会绝不吝啬 感谢CSDN让你我相遇 前言
  • 【vue】npm install -g @vue/cli出现错误

    进行到npm install g vue cli这一步出现错误 操作步骤如下 1 先下载node js 不知道有没有下载 可以在cmd输入 node v 出现版本号则电脑已经有了node js 没有的话去官网下一个 csdn有其他小伙伴给了
  • Spring Boot全后端实现验证码

    验证码通常是利用前端技术实现的 前端的验证码需要先在后端进行保存 再传到前端 再于前端传输的数据对比校验 一些前后端分离项目的工作量大大增加 而如果完全是由后端独立实现的 那么在代码量和复杂程度上就大大降低了 框架 Spring Boot
  • JavaWeb使用ajax实现定时自动保存草稿功能

    在Web程序开发中 难免有时候会遇到一些定时业务 如考试系统中的自动提交试卷 还有平时写博客时定时自动保存草稿的功能 在JavaWeb中也可以利用ajax技术来实现这定时自动保存草稿这一功能 index jsp关键代码 html代码 加载时
  • 编写QT程序时发现内存泄漏的解决方法

    最近项目结尾进行测试的时候 发现项目持续运行产生大量数据后内存的消耗会无休止的增加 当关闭该窗口时 内存却并没有如期释放 理论上QT中所有的子对象在窗口被销毁时都会一同销毁 最终发现是我在这篇博客上写的添加长按的效果导致的 https bl
  • ipynb 格式文件

    最近碰到文件名后缀为 ipynb文件 起初没太在意这种文件格式 用Notepad 打开之后看到也是类似于JSON格式的信息 以为也是为其他的一些文件服务的 类似于配置一些HTML文件的配置文件 但是后来才发现这也是一种文本表示形式 只不过需
  • Lua:调试篇

    1 Lua代码编辑工具 辣博推荐 ZeroBrane Studio编写Lua脚本还是不错滴 基本的代码补全和提示都具有 按照从下往上的代码逻辑 还可以自动对齐格式 实话讲 还不是很完美 毕竟 作为一个使用习惯Qt如此完美的IDE工具的 Qt
  • [线性dp] aw897. 最长公共子序列(重要模板题+最长公共子序列模型)

    文章目录 0 前言 1 LCS 模板题 0 前言 LCS longest common sub sequences 最长公共子序列 子串 按原顺序依次出现 禁止跳过某元素的序列 具有连续性 子序列 在保持元素前后关系的前提下 可以跳过某些元
  • C语言文件指针设置偏移量--fseek

    一 fseek fseek是设置文件指针偏移量的函数 具体传参格式为 int fseek FILE stream long int offset int whence 返回一个整数 其中 1 stream是指向文件的指针 2 offset是
  • (亲测可用)html5 file调用手机摄像头

    在切图网一个客户的webapp项目中需要用到 html5调用手机摄像头 找了很多资料 大都是 js调用api 然后怎样怎样 做了几个demo测试发现根本不行 后来恍然大悟 用html5自带的 input file 纯html5 并且不涉及到
  • composer.json和composer.lock到底是什么以及区别?

    composer方文档 https docs phpcomposer com 04 schema html我们在做项目的时候 总是要安装一些依赖 composer给我们提供了很多方便 直接运行composer install 当我们运行co
  • Keras 深度学习之猫狗大战

    项目地址和代码 Project Dogs vs Cats 项目详细报告 Report dogs vs cats pdf keras 版本 2 1 5使用滴滴云AI大师码 0212 消费GPU有9折优惠哦 1 问题定义和数据集获取 项目属于计
  • Android RecyclerView 实现瀑布流

    Android RecyclerView 使用大全 基础使用 item 动画 下拉刷新等 瀑布流也是个常用的显示控件了 但是在使用时经常遇到一些问题 比如滑动回顶部后出现空隙 item在滑动时乱跳等问题 下面就来说说我怎么实现的瀑布流 并且