当前位置: 首页 > news >正文

Android通过Recyclerview实现流式布局自适应列数及高度

在这里插入图片描述

调用 FlowAdapter 跟普通recyclerview一样使用

RecyclerView rvLayout = holder.getView(R.id.spe_tag_layout);
FlowAdapter rvAdapter = new FlowAdapter();
FlowLayoutManager flowLayoutManager = new FlowLayoutManager();
rvLayout.setLayoutManager(flowLayoutManager);
rvLayout.setAdapter(rvAdapter);

/*** date:2024/1/10* author:wsm* describe:一种流式布局的LayoutManager*/
public class FlowLayoutManager extends RecyclerView.LayoutManager {private static final String TAG = FlowLayoutManager.class.getSimpleName();final FlowLayoutManager self = this;protected int width, height;private int left, top, right;//最大容器的宽度private int usedMaxWidth;//竖直方向上的偏移量private int verticalScrollOffset = 0;public int getTotalHeight() {return totalHeight;}//计算显示的内容的高度protected int totalHeight = 0;private Row row = new Row();private List<Row> lineRows = new ArrayList<>();//保存所有的Item的上下左右的偏移量信息private SparseArray<Rect> allItemFrames = new SparseArray<>();public FlowLayoutManager() {//设置主动测量规则,适应recyclerView高度为wrap_contentsetAutoMeasureEnabled(true);}//每个item的定义public class Item {int useHeight;View view;public void setRect(Rect rect) {this.rect = rect;}Rect rect;public Item(int useHeight, View view, Rect rect) {this.useHeight = useHeight;this.view = view;this.rect = rect;}}//行信息的定义public class Row {public void setCuTop(float cuTop) {this.cuTop = cuTop;}public void setMaxHeight(float maxHeight) {this.maxHeight = maxHeight;}//每一行的头部坐标float cuTop;//每一行需要占据的最大高度float maxHeight;//每一行存储的itemList<Item> views = new ArrayList<>();public void addViews(Item view) {views.add(view);}}@Overridepublic RecyclerView.LayoutParams generateDefaultLayoutParams() {return new RecyclerView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);}//该方法主要用来获取每一个item在屏幕上占据的位置@Overridepublic void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {Log.d(TAG, "onLayoutChildren");totalHeight = 0;int cuLineTop = top;//当前行使用的宽度int cuLineWidth = 0;int itemLeft;int itemTop;int maxHeightItem = 0;row = new Row();lineRows.clear();allItemFrames.clear();removeAllViews();if (getItemCount() == 0) {detachAndScrapAttachedViews(recycler);verticalScrollOffset = 0;return;}if (getChildCount() == 0 && state.isPreLayout()) {return;}//onLayoutChildren方法在RecyclerView 初始化时 会执行两遍detachAndScrapAttachedViews(recycler);if (getChildCount() == 0) {width = getWidth();height = getHeight();left = getPaddingLeft();right = getPaddingRight();top = getPaddingTop();usedMaxWidth = width - left - right;}for (int i = 0; i < getItemCount(); i++) {Log.d(TAG, "index:" + i);View childAt = recycler.getViewForPosition(i);if (View.GONE == childAt.getVisibility()) {continue;}measureChildWithMargins(childAt, 0, 0);int childWidth = getDecoratedMeasuredWidth(childAt);int childHeight = getDecoratedMeasuredHeight(childAt);int childUseWidth = childWidth;int childUseHeight = childHeight;//如果加上当前的item还小于最大的宽度的话if (cuLineWidth + childUseWidth <= usedMaxWidth) {itemLeft = left + cuLineWidth;itemTop = cuLineTop;Rect frame = allItemFrames.get(i);if (frame == null) {frame = new Rect();}frame.set(itemLeft, itemTop, itemLeft + childWidth, itemTop + childHeight);allItemFrames.put(i, frame);cuLineWidth += childUseWidth;maxHeightItem = Math.max(maxHeightItem, childUseHeight);row.addViews(new Item(childUseHeight, childAt, frame));row.setCuTop(cuLineTop);row.setMaxHeight(maxHeightItem);} else {//换行formatAboveRow();cuLineTop += maxHeightItem;totalHeight += maxHeightItem;itemTop = cuLineTop;itemLeft = left;Rect frame = allItemFrames.get(i);if (frame == null) {frame = new Rect();}frame.set(itemLeft, itemTop, itemLeft + childWidth, itemTop + childHeight);allItemFrames.put(i, frame);cuLineWidth = childUseWidth;maxHeightItem = childUseHeight;row.addViews(new Item(childUseHeight, childAt, frame));row.setCuTop(cuLineTop);row.setMaxHeight(maxHeightItem);}//不要忘了最后一行进行刷新下布局if (i == getItemCount() - 1) {formatAboveRow();totalHeight += maxHeightItem;}}totalHeight = Math.max(totalHeight, getVerticalSpace());Log.d(TAG, "onLayoutChildren totalHeight:" + totalHeight);fillLayout(recycler, state);}//对出现在屏幕上的item进行展示,超出屏幕的item回收到缓存中private void fillLayout(RecyclerView.Recycler recycler, RecyclerView.State state) {if (state.isPreLayout() || getItemCount() == 0) { // 跳过preLayout,preLayout主要用于支持动画return;}// 当前scroll offset状态下的显示区域Rect displayFrame = new Rect(getPaddingLeft(), getPaddingTop() + verticalScrollOffset,getWidth() - getPaddingRight(), verticalScrollOffset + (getHeight() - getPaddingBottom()));//对所有的行信息进行遍历for (int j = 0; j < lineRows.size(); j++) {Row row = lineRows.get(j);float lineTop = row.cuTop;float lineBottom = lineTop + row.maxHeight;//如果该行在屏幕中,进行放置item
//            if (lineTop < displayFrame.bottom && displayFrame.top < lineBottom) {List<Item> views = row.views;for (int i = 0; i < views.size(); i++) {View scrap = views.get(i).view;measureChildWithMargins(scrap, 0, 0);addView(scrap);Rect frame = views.get(i).rect;//将这个item布局出来layoutDecoratedWithMargins(scrap,frame.left,frame.top - verticalScrollOffset,frame.right,frame.bottom - verticalScrollOffset);}
//            } else {
//                //将不在屏幕中的item放到缓存中
//                List<Item> views = row.views;
//                for (int i = 0; i < views.size(); i++) {
//                    View scrap = views.get(i).view;
//                    removeAndRecycleView(scrap, recycler);
//                }
//            }}}/*** 计算每一行没有居中的viewgroup,让居中显示*/private void formatAboveRow() {List<Item> views = row.views;for (int i = 0; i < views.size(); i++) {Item item = views.get(i);View view = item.view;int position = getPosition(view);//如果该item的位置不在该行中间位置的话,进行重新放置if (allItemFrames.get(position).top < row.cuTop + (row.maxHeight - views.get(i).useHeight) / 2) {Rect frame = allItemFrames.get(position);if (frame == null) {frame = new Rect();}frame.set(allItemFrames.get(position).left, (int) (row.cuTop + (row.maxHeight - views.get(i).useHeight) / 2),allItemFrames.get(position).right, (int) (row.cuTop + (row.maxHeight - views.get(i).useHeight) / 2 + getDecoratedMeasuredHeight(view)));allItemFrames.put(position, frame);item.setRect(frame);views.set(i, item);}}row.views = views;lineRows.add(row);row = new Row();}/*** 竖直方向需要滑动的条件** @return*/@Overridepublic boolean canScrollVertically() {return true;}//监听竖直方向滑动的偏移量@Overridepublic int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler,RecyclerView.State state) {Log.d("TAG", "totalHeight:" + totalHeight);//实际要滑动的距离int travel = dy;//如果滑动到最顶部if (verticalScrollOffset + dy < 0) {//限制滑动到顶部之后,不让继续向上滑动了travel = -verticalScrollOffset;//verticalScrollOffset=0} else if (verticalScrollOffset + dy > totalHeight - getVerticalSpace()) {//如果滑动到最底部travel = totalHeight - getVerticalSpace() - verticalScrollOffset;//verticalScrollOffset=totalHeight - getVerticalSpace()}//将竖直方向的偏移量+travelverticalScrollOffset += travel;// 平移容器内的itemoffsetChildrenVertical(-travel);fillLayout(recycler, state);return travel;}private int getVerticalSpace() {return self.getHeight() - self.getPaddingBottom() - self.getPaddingTop();}public int getHorizontalSpace() {return self.getWidth() - self.getPaddingLeft() - self.getPaddingRight();}
}

相关文章:

Android通过Recyclerview实现流式布局自适应列数及高度

调用 FlowAdapter 跟普通recyclerview一样使用 RecyclerView rvLayout holder.getView(R.id.spe_tag_layout); FlowAdapter rvAdapter new FlowAdapter(); FlowLayoutManager flowLayoutManager new FlowLayoutManager(); rvLayout.setLayoutManager(flowLayoutManager); r…...

AlexNet(fashion-mnist)

前言 AlexNet相较于LeNet-5具有更深的网络结构&#xff0c;采用relu激活函数。 AlexNet 参数更多&#xff0c;计算量更大&#xff0c;计算速度更慢&#xff0c;精度更高。 netnn.Sequential(nn.Conv2d(1,96,kernel_size11,stride4,padding1),nn.ReLU(),nn.MaxPool2d(kernel…...

2024新年烟花代码完整版

文章目录 前言烟花效果展示使用教程查看源码HTML代码CSS代码JavaScript 新年祝福 前言 在这个充满希望和激动的2024年&#xff0c;新的一年即将拉开帷幕&#xff0c;而数字科技的创新与发展也如火如荼。烟花绚丽多彩的绽放&#xff0c;一直以来都是新年庆典中不可或缺的元素。…...

Fontfabric:一款字体与设计的完美结合

一、产品介绍 Fontfabric是一款由国际字体设计公司Fontfabric开发的字体设计软件。它提供了一整套完整的字体设计工具&#xff0c;让用户可以轻松地创建、设计和定制自己的字体。Fontfabric拥有丰富的字体库&#xff0c;包括各种风格和类型&#xff0c;能够满足用户在不同场景…...

Python爬虫—requests模块简单应用

Python爬虫—requests模块简介 requests的作用与安装 作用&#xff1a;发送网络请求&#xff0c;返回响应数据 安装&#xff1a;pip install requests requests模块发送简单的get请求、获取响应 需求&#xff1a;通过requests向百度首页发送请求&#xff0c;获取百度首页的…...

江科大STM32

参考&#xff1a; https://blog.csdn.net/weixin_54742551/article/details/132409170?spm1001.2014.3001.5502 https://blog.csdn.net/Johnor/article/details/128539267?spm1001.2014.3001.5502 SPI&#xff1a;https://blog.csdn.net/weixin_62127790/article/details/132…...

银河麒麟Kylin-Server-V10-SP3使用ISO镜像搭建本地内网YUM/DNF源cdrom/http

机房服务器安装一般是内网环境&#xff0c;需要配置本地的YUM/DNF源。本文介绍通过ISO镜像搭建内网环境的UM/DNF源 准备工作&#xff1a; 提前准备好Kylin-Server-V10-SP3的ISO镜像文件。 本机IP地址&#xff1a;192.168.40.201 镜像存放目录/data/iso/Kylin-Server-V10-SP3-Ge…...

力扣第 379 场周赛VP

目录 一1.思路2.代码 二1.思路2.代码 三1.思路2.代码 四1.思路2.代码 链接:https://leetcode.cn/contest/weekly-contest-379/ 一 1.思路 找最长对角线&#xff0c;很显然直接比较a^2 b ^ 2就行 注意更新时考虑对角线长度相等时候去面积最大 2.代码 class Solution { publ…...

String intern()方法

String intern 方法有什么作用? String.intern() 是一个 native&#xff08;本地&#xff09;方法&#xff0c;其作用是将指定的字符串对象的引用保存在字符串常量池中&#xff0c;并返回常量池中对应的字符串引用。 当使用字面量创建字符串时&#xff0c;Java 会在编译期间自…...

springboot 物业管理系统

springboot mysql mybatisthymeleaf 基础信息管理 房屋信息 用户信息 业主信息 租房信息 公告管理 日常管理 财务管理...

K8S--- kubectl auth

该命令可以校验用户或者serviceaccount是否有对应的权限 [root@yyzc-zjjcs01 ~]# /opt/kubernetes/bin/kubectl --kubeconfig /opt/kubernetes/conf/default-admin.kubeconfig auth --help Inspect authorization Available Commands: can-i Check whether an action is allowe…...

HarmonyOS 开发基础(九)forEach

HarmonyOS 开发基础&#xff08;九&#xff09;forEach 一、基础使用 Entry Component struct Index {// 创建一个变量&#xff0c;用来存储图片网络网址imageUrl: string https://gw.alicdn.com/imgextra/i2/2201227850912/O1CN01B7gVvP1Ibk6HMiDRz_!!2201227850912.jpg_Q75.…...

【小黑嵌入式系统第十四课】μC/OS-III程序设计基础(三)——信号量(任务同步资源同步)、事件标记组(与或多个任务)

上一课&#xff1a; 【小黑嵌入式系统第十三课】PSoC 5LP第二个实验——中断控制实验 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站&#xff1a;人工智能 文章目录 1 信号量1.1 简介1.2…...

PMP报考流程?

项目管理相关证书&#xff0c;PMP是一个不错的选择&#xff0c;尤其是小白朋友。 PMP 是项目管理的一个入门证书&#xff0c;理论知识很全面&#xff0c;涵盖了项目管理的全流程&#xff0c;可作为日常工具参考书、完全小白的可以先考一个PMP学好理论&#xff0c;再考一个PRIN…...

【EI会议征稿通知】2024年机器学习与智能计算国际学术会议(MLIC 2024)

2024年机器学习与智能计算国际学术会议&#xff08;MLIC 2024&#xff09; 2024 International Conference on Machine learning and intelligent computing 智能计算与机器学习被广泛应用于大数据分析、人工智能、智能制造、智能交通、智能电网、智慧城市、智慧医疗、金融科…...

第八篇 提升网页性能:深入解析HTTP请求优化策略(三)

文章目录 1. 缓存策略设计1.1 HTTP缓存机制1.1.1 强缓存&#xff08;Cache-Control/Expires&#xff09;1.1.2 协商缓存&#xff08;ETag/Last-Modified&#xff09; 1.2 缓存位置1.2.1 浏览器缓存1.2.2 代理服务器缓存 1.3 缓存策略选择1.3.1私有缓存1.3.2 公共资源缓存 1.4 V…...

高版本ant-design动态引用icon

需求 最近在更新自己的博客系统&#xff0c;从 vue2 升到 vue3&#xff0c;同步的也把 ant-design 从 1.7.8 跨越多个大版本升级到了 4.0.8&#xff0c;发现菜单上的 icon 报错了。 查询官方文档发现自从 2.0 版本以后的 icon 就不再支持通过 <a-icon /> 组件动态 type…...

【SQL】delete 与 truncate 命令的区别

区别 truncatedelete属于 DDL(数据定义语言) 范畴属于 DML(数据操作语言) 范畴删除表数据&#xff0c;不能删除视图数据删除表数据&#xff0c;删除视图数据只可以梭哈删除通过 where 进行选择性删除不涉及事务处理删除表中数据涉及事务处理效率高、但无法撤销效率低&#xff…...

【ITK库学习】使用itk库进行图像分割(四):水平集分割

目录 1、水平集2、itkFastMarchingImageFilter 快速步进分割3、itkShapeDetectionLevelSetImageFilter 快速步进分割 1、水平集 水平集是跟踪轮廓和表面运动的一种数字化方法。基于图像的亮度均值、梯度、边缘特征的微分计算&#xff0c;进行水平集分割。在itk中&#xff0c;所…...

Kali Linux——aircrack-ng无线教程

目录 一、准备 二、案例 1、连接usb无线网卡 2、查看网卡信息 3、开启网卡监听 4、扫描wifi信号 5、抓取握手包 6、强制断开连接 7、破解握手包 三、预防 一、准备 1、usb无线网卡&#xff08;笔记本也是需要用到&#xff09; 2、密码字典&#xff08;Kali 系统自带…...

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…...

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…...

地震勘探——干扰波识别、井中地震时距曲线特点

目录 干扰波识别反射波地震勘探的干扰波 井中地震时距曲线特点 干扰波识别 有效波&#xff1a;可以用来解决所提出的地质任务的波&#xff1b;干扰波&#xff1a;所有妨碍辨认、追踪有效波的其他波。 地震勘探中&#xff0c;有效波和干扰波是相对的。例如&#xff0c;在反射波…...

苍穹外卖--缓存菜品

1.问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得&#xff0c;如果用户端访问量比较大&#xff0c;数据库访问压力随之增大 2.实现思路 通过Redis来缓存菜品数据&#xff0c;减少数据库查询操作。 缓存逻辑分析&#xff1a; ①每个分类下的菜品保持一份缓存数据…...

ElasticSearch搜索引擎之倒排索引及其底层算法

文章目录 一、搜索引擎1、什么是搜索引擎?2、搜索引擎的分类3、常用的搜索引擎4、搜索引擎的特点二、倒排索引1、简介2、为什么倒排索引不用B+树1.创建时间长,文件大。2.其次,树深,IO次数可怕。3.索引可能会失效。4.精准度差。三. 倒排索引四、算法1、Term Index的算法2、 …...

大模型多显卡多服务器并行计算方法与实践指南

一、分布式训练概述 大规模语言模型的训练通常需要分布式计算技术,以解决单机资源不足的问题。分布式训练主要分为两种模式: 数据并行:将数据分片到不同设备,每个设备拥有完整的模型副本 模型并行:将模型分割到不同设备,每个设备处理部分模型计算 现代大模型训练通常结合…...

c#开发AI模型对话

AI模型 前面已经介绍了一般AI模型本地部署&#xff0c;直接调用现成的模型数据。这里主要讲述讲接口集成到我们自己的程序中使用方式。 微软提供了ML.NET来开发和使用AI模型&#xff0c;但是目前国内可能使用不多&#xff0c;至少实践例子很少看见。开发训练模型就不介绍了&am…...

Linux 内存管理实战精讲:核心原理与面试常考点全解析

Linux 内存管理实战精讲&#xff1a;核心原理与面试常考点全解析 Linux 内核内存管理是系统设计中最复杂但也最核心的模块之一。它不仅支撑着虚拟内存机制、物理内存分配、进程隔离与资源复用&#xff0c;还直接决定系统运行的性能与稳定性。无论你是嵌入式开发者、内核调试工…...

【网络安全】开源系统getshell漏洞挖掘

审计过程&#xff1a; 在入口文件admin/index.php中&#xff1a; 用户可以通过m,c,a等参数控制加载的文件和方法&#xff0c;在app/system/entrance.php中存在重点代码&#xff1a; 当M_TYPE system并且M_MODULE include时&#xff0c;会设置常量PATH_OWN_FILE为PATH_APP.M_T…...

在 Spring Boot 中使用 JSP

jsp&#xff1f; 好多年没用了。重新整一下 还费了点时间&#xff0c;记录一下。 项目结构&#xff1a; pom: <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://ww…...