我的编程空间,编程开发者的网络收藏夹
学习永远不晚

使用RecyclerView实现瀑布流高度自适应

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

使用RecyclerView实现瀑布流高度自适应

使用RecyclerView实现的瀑布流高度自适应,供大家参考,具体内容如下

背景:使用时在RecyclerView外嵌套了自定义的ScrollView,需要让RecyclerView高度自适应,由于是瀑布流格式网上找了好多方法都无法实现或是动态计算的高度不准确。估计大家都知道recyclerview 内容的高度不是 recyclerview 控制的而是由LayoutManager 来设置的。下面我来说下我的解决方案吧:

布局中的使用


<android.support.v7.widget.RecyclerView
                android:id="@+id/rcv_indexfragment_article_list"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="@dimen/dimen12"
                android:padding="@dimen/dimen4"
                android:background="@color/bg_white"/>

方法一

个人认为最简单有效的方法,解决问题最终选用的方法。

官网博客翻译资料:

RecyclerView 控件提供了灵活一种创建列表和网格的基本方案,而且还支持动画。这个版本为 LayoutManager API带来了一个非常激动人心的新特性:自动测量!让RecyclerView可以根据其内容的大小调整自己。这意味着以前那些无解的场景,比如对RecyclerView的一个dimension 使用WRAP_CONTENT成为了可能。你会发现所有的内置LayoutManager现在都支持自动测量。
因为这个变化的原因,你得仔细检查 item view的 layout parameters 了:以前会被自动忽略的 layout parameters(比如在滚动方向上的MATCH_PARENT ),现在会被完全考虑进去。如果你有一个自定义的LayoutManager,且没有继承自内置的LayoutManager,那么这就是一个可选的API - 你需要调用setAutoMeasureEnabled(true) 并且根据这个方法的Javadoc中的描述做一些微小的改变。
注意,虽然RecyclerView可以让自己的子View动画,但是它不能动画自己的边界改变。如果你想要让RecyclerView的边界变化也呈现动画,你可以使用 Transition API。

配置的版本:


compile 'com.android.support:recyclerview-v7:23.2.1'

想要内容随高度变化需设置:(注意:此方式是Android Support Library 23.2中引入的,如果配置之前的版本会报错哦~)


layoutManager.setAutoMeasureEnabled(true);

Activity中的使用:


recyclerview= ViewFindUtils.find(view, R.id.recyclerview);
StaggeredGridLayoutManager layoutManager = new StaggeredGridLayoutManager(2,StaggeredGridLayoutManager.VERTICAL);
        layoutManager.setAutoMeasureEnabled(true);
recyclerview.setLayoutManager(layoutManager);
recyclerview.setHasFixedSize(true);
recyclerview.setNestedScrollingEnabled(false);
SpacesItemDecoration decoration = new SpacesItemDecoration(6);
recyclerview.addItemDecoration(decoration);

方法二

自定义CustomStaggeredGridLayoutManager类继承自StaggeredGridLayoutManager。(注:此方法用到我的项目中计算的高度不准确,列表后面总有一段空白,所以我放弃了~不过你们可以试试,可能是我布局嵌套的问题)

配置的版本(建议使用最新的版本):


compile 'com.android.support:recyclerview-v7:23.1.1'

Activity中的使用:


recyclerview= ViewFindUtils.find(view, R.id.recyclerview);
CustomStaggeredGridLayoutManager layoutManager = new CustomStaggeredGridLayoutManager(2,StaggeredGridLayoutManager.VERTICAL);
recyclerview.setLayoutManager(layoutManager);
recyclerview.setHasFixedSize(true);
recyclerview.setNestedScrollingEnabled(false);
SpacesItemDecoration decoration = new SpacesItemDecoration(6);
recyclerview.addItemDecoration(decoration);

SpacesItemDecoration.class


public class SpacesItemDecoration extends RecyclerView.ItemDecoration {

        private int space;

        public SpacesItemDecoration(int space) {
            this.space = space;
        }

        @Override
        public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
            outRect.top = space;
            outRect.bottom = space;
            outRect.left = space;
            outRect.right = space;
        }
    }

CustomStaggeredGridLayoutManager.class


package com.sunny.demo.widget;

import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.StaggeredGridLayoutManager;
import android.view.View;
import android.view.ViewGroup;

import com.parkmecn.ehc.utils.LogUtil;


public class CustomStaggeredGridLayoutManager extends StaggeredGridLayoutManager {
    public CustomStaggeredGridLayoutManager(int spanCount, int orientation) {
        super(spanCount, orientation);
    }

    // 尺寸的数组,[0]是宽,[1]是高
    private int[] measuredDimension = new int[2];

    // 用来比较同行/列那个item罪宽/高
    private int[] dimension;


    @Override

    public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state, int widthSpec, int heightSpec) {
        // 宽的mode+size
        final int widthMode = View.MeasureSpec.getMode(widthSpec);
        final int widthSize = View.MeasureSpec.getSize(widthSpec);
        // 高的mode + size
        final int heightMode = View.MeasureSpec.getMode(heightSpec);
        final int heightSize = View.MeasureSpec.getSize(heightSpec);

        // 自身宽高的初始值
        int width = 0;
        int height = 0;
        // item的数目
        int count = getItemCount();
        // item的列数
        int span = getSpanCount();
        // 根据行数或列数来创建数组
        dimension = new int[span];

        for (int i = 0; i < count; i++) {
            measureScrapChild(recycler, i, View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED), View
                    .MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED), measuredDimension);

            // 如果是竖直的列表,计算item的高,否则计算宽度
//            LogUtil.d("LISTENER", "position " + i + " height = " + measuredDimension[1]);
            if (getOrientation() == VERTICAL) {
                dimension[findMinIndex(dimension)] += measuredDimension[1];
            } else {
                dimension[findMinIndex(dimension)] += measuredDimension[0];
            }
        }
        if (getOrientation() == VERTICAL) {
            height = findMax(dimension);
        } else {
            width = findMax(dimension);
        }


        switch (widthMode) {
            // 当控件宽是match_parent时,宽度就是父控件的宽度
            case View.MeasureSpec.EXACTLY:
                width = widthSize;
                break;
            case View.MeasureSpec.AT_MOST:
                break;
            case View.MeasureSpec.UNSPECIFIED:
                break;
        }
        switch (heightMode) {
            // 当控件高是match_parent时,高度就是父控件的高度
            case View.MeasureSpec.EXACTLY:
                height = heightSize;
                break;
            case View.MeasureSpec.AT_MOST:
                break;
            case View.MeasureSpec.UNSPECIFIED:
                break;
        }
        // 设置测量尺寸
        setMeasuredDimension(width, height);
        LogUtil.e("setMeasuredDimension(width, height)--->height==" + height);
    }

    private void measureScrapChild(RecyclerView.Recycler recycler, int position, int widthSpec, int heightSpec, int[]
            measuredDimension) {

        // 挨个遍历所有item
        if (position < getItemCount()) {
            try {
                View view = recycler.getViewForPosition(position);//fix 动态添加时报IndexOutOfBoundsException

                if (view != null) {
                    RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams) view.getLayoutParams();
                    int childWidthSpec = ViewGroup.getChildMeasureSpec(widthSpec, getPaddingLeft() + getPaddingRight
                            (), lp.width);
                    LogUtil.e(position + "--->heightSpec=" + heightSpec + ";getPaddingTop()=" + getPaddingTop() + ";" +
                            "getPaddingBottom()" + getPaddingBottom() + ";lp.height=" + lp.height);
                    int childHeightSpec = ViewGroup.getChildMeasureSpec(heightSpec, getPaddingTop() +
                            getPaddingBottom(), lp.height);
                    LogUtil.e(position + "--->viewchildHeightSpec=" + childHeightSpec);
                    // 子view进行测量,然后可以通过getMeasuredWidth()获得测量的宽,高类似
                    view.measure(childWidthSpec, childHeightSpec);
                    // 将item的宽高放入数组中
                    measuredDimension[0] = view.getMeasuredWidth() + lp.leftMargin + lp.rightMargin;
                    //FIXME 此处计算的高度总比实际高度要高一些,导致最后RecycerView的高度计算不对最后留有一段空白,暂时没有找到问题所在,待大神的解决啊~
                    measuredDimension[1] = view.getMeasuredHeight() + lp.topMargin + lp.bottomMargin;
                    LogUtil.e(position + "--->view.getMeasuredHeight()=" + view.getMeasuredHeight() + ";lp" +
                            ".topMargin=" + lp.topMargin + ";lp.bottomMargin=" + lp.bottomMargin);
                    recycler.recycleView(view);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    private int findMax(int[] array) {
        int max = array[0];
        for (int value : array) {
            if (value > max) {
                max = value;
            }
        }
        return max;
    }

    
    private int findMinIndex(int[] array) {
        int index = 0;
        int min = array[0];
        for (int i = 0; i < array.length; i++) {
            if (array[i] < min) {
                min = array[i];
                index = i;
            }
        }
        return index;
    }


}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程网。

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

使用RecyclerView实现瀑布流高度自适应

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Android RecyclerView实现瀑布流,图片自适应高度,不闪烁,解决位置交换

记录一下以前自己代码中用到过代码效果,也做个备份,省的以后代码找不到,大家也可以参考参考,也许看过网上某些笔记,但是不记得了链接了,有问题可以联系本人 以下会写从布局到java代码以及用到的工具类都写出来,供大家参考 一、首先上两个布局xm
2022-06-06

Android怎么使用RecyclerView实现瀑布流界面

今天小编给大家分享一下Android怎么使用RecyclerView实现瀑布流界面的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下
2023-07-05

Android入门之使用RecyclerView完美实现瀑布流界面详解

网上充满着不完善的基于RecyclerView的瀑布流实现,要么根本是错的、要么就是只知其一不知其二。本文就来用RecyclerView完美实现瀑布流界面,希望大家有所帮助
2023-02-22

使用postMessage怎么实现iframe自适应高度

这篇文章将为大家详细讲解有关使用postMessage怎么实现iframe自适应高度,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。index.html :
2023-06-09

css怎么实现高度自适应

本篇内容主要讲解“css怎么实现高度自适应”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“css怎么实现高度自适应”吧!在写css静态页面的时候让Html的高度自适应屏幕高度是一个常见的需求,比如
2023-06-20

怎么在HTML5中使用 textarea实现高度自适应

今天就跟大家聊聊有关怎么在HTML5中使用 textarea实现高度自适应,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。方案一HTML5 Textarea 元素1. 自动获得焦点点击
2023-06-09

使用CSS实现响应式卡片瀑布流布局的技巧

使用CSS实现响应式卡片瀑布流布局的技巧随着移动设备的普及和网页内容的多样化,响应式设计已经成为现代web开发的基本要求之一。其中,卡片式布局和瀑布流布局都逐渐成为广受欢迎的设计风格。本文将介绍如何使用CSS实现一个响应式的卡片瀑布流布局,
使用CSS实现响应式卡片瀑布流布局的技巧
2023-11-21

使用CSS实现响应式瀑布流卡片布局的技巧

使用CSS实现响应式瀑布流卡片布局的技巧,需要具体代码示例在当今移动设备普及的时代,响应式设计已经成为现代网站的必备要素之一。而响应式瀑布流卡片布局作为一种流行的布局方式,可以在不同屏幕尺寸下实现流畅的展示效果。本文将介绍如何使用CSS实现
使用CSS实现响应式瀑布流卡片布局的技巧
2023-11-21

使用CSS3怎么实现一个瀑布流布局

使用CSS3怎么实现一个瀑布流布局?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。掌握点:1、column-count 把div中的文本分为多少列2、column-width 规
2023-06-08

如何使用HTML和CSS实现瀑布流布局

如何使用HTML和CSS实现瀑布流布局瀑布流布局(Waterfall Layout)是一种常见的网页布局方式,它可以使网页内容呈现出像瀑布流一样的效果,每一列的高度可以不同,让网页看起来更加有趣和动感。在这篇文章中,我们将介绍如何使用HTM
2023-10-24

编程热搜

  • Android:VolumeShaper
    VolumeShaper(支持版本改一下,minsdkversion:26,android8.0(api26)进一步学习对声音的编辑,可以让音频的声音有变化的播放 VolumeShaper.Configuration的三个参数 durati
    Android:VolumeShaper
  • Android崩溃异常捕获方法
    开发中最让人头疼的是应用突然爆炸,然后跳回到桌面。而且我们常常不知道这种状况会何时出现,在应用调试阶段还好,还可以通过调试工具的日志查看错误出现在哪里。但平时使用的时候给你闹崩溃,那你就欲哭无泪了。 那么今天主要讲一下如何去捕捉系统出现的U
    Android崩溃异常捕获方法
  • android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
    系统的设置–>电池–>使用情况中,统计的能耗的使用情况也是以power_profile.xml的value作为基础参数的1、我的手机中power_profile.xml的内容: HTC t328w代码如下:
    android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
  • Android SQLite数据库基本操作方法
    程序的最主要的功能在于对数据进行操作,通过对数据进行操作来实现某个功能。而数据库就是很重要的一个方面的,Android中内置了小巧轻便,功能却很强的一个数据库–SQLite数据库。那么就来看一下在Android程序中怎么去操作SQLite数
    Android SQLite数据库基本操作方法
  • ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
    工作的时候为了方便直接打开编辑文件,一些常用的软件或者文件我们会放在桌面,但是在ubuntu20.04下直接直接拖拽文件到桌面根本没有效果,在进入桌面后发现软件列表中的软件只能收藏到面板,无法复制到桌面使用,不知道为什么会这样,似乎并不是很
    ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
  • android获取当前手机号示例程序
    代码如下: public String getLocalNumber() { TelephonyManager tManager =
    android获取当前手机号示例程序
  • Android音视频开发(三)TextureView
    简介 TextureView与SurfaceView类似,可用于显示视频或OpenGL场景。 与SurfaceView的区别 SurfaceView不能使用变换和缩放等操作,不能叠加(Overlay)两个SurfaceView。 Textu
    Android音视频开发(三)TextureView
  • android获取屏幕高度和宽度的实现方法
    本文实例讲述了android获取屏幕高度和宽度的实现方法。分享给大家供大家参考。具体分析如下: 我们需要获取Android手机或Pad的屏幕的物理尺寸,以便于界面的设计或是其他功能的实现。下面就介绍讲一讲如何获取屏幕的物理尺寸 下面的代码即
    android获取屏幕高度和宽度的实现方法
  • Android自定义popupwindow实例代码
    先来看看效果图:一、布局
  • Android第一次实验
    一、实验原理 1.1实验目标 编程实现用户名与密码的存储与调用。 1.2实验要求 设计用户登录界面、登录成功界面、用户注册界面,用户注册时,将其用户名、密码保存到SharedPreference中,登录时输入用户名、密码,读取SharedP
    Android第一次实验

目录