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具有更深的网络结构,采用relu激活函数。 AlexNet 参数更多,计算量更大,计算速度更慢,精度更高。 netnn.Sequential(nn.Conv2d(1,96,kernel_size11,stride4,padding1),nn.ReLU(),nn.MaxPool2d(kernel…...

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

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

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

江科大STM32
参考: 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:https://blog.csdn.net/weixin_62127790/article/details/132…...

银河麒麟Kylin-Server-V10-SP3使用ISO镜像搭建本地内网YUM/DNF源cdrom/http
机房服务器安装一般是内网环境,需要配置本地的YUM/DNF源。本文介绍通过ISO镜像搭建内网环境的UM/DNF源 准备工作: 提前准备好Kylin-Server-V10-SP3的ISO镜像文件。 本机IP地址: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.思路 找最长对角线,很显然直接比较a^2 b ^ 2就行 注意更新时考虑对角线长度相等时候去面积最大 2.代码 class Solution { publ…...
String intern()方法
String intern 方法有什么作用? String.intern() 是一个 native(本地)方法,其作用是将指定的字符串对象的引用保存在字符串常量池中,并返回常量池中对应的字符串引用。 当使用字面量创建字符串时,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 开发基础(九)forEach 一、基础使用 Entry Component struct Index {// 创建一个变量,用来存储图片网络网址imageUrl: string https://gw.alicdn.com/imgextra/i2/2201227850912/O1CN01B7gVvP1Ibk6HMiDRz_!!2201227850912.jpg_Q75.…...

【小黑嵌入式系统第十四课】μC/OS-III程序设计基础(三)——信号量(任务同步资源同步)、事件标记组(与或多个任务)
上一课: 【小黑嵌入式系统第十三课】PSoC 5LP第二个实验——中断控制实验 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站:人工智能 文章目录 1 信号量1.1 简介1.2…...

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

【EI会议征稿通知】2024年机器学习与智能计算国际学术会议(MLIC 2024)
2024年机器学习与智能计算国际学术会议(MLIC 2024) 2024 International Conference on Machine learning and intelligent computing 智能计算与机器学习被广泛应用于大数据分析、人工智能、智能制造、智能交通、智能电网、智慧城市、智慧医疗、金融科…...
第八篇 提升网页性能:深入解析HTTP请求优化策略(三)
文章目录 1. 缓存策略设计1.1 HTTP缓存机制1.1.1 强缓存(Cache-Control/Expires)1.1.2 协商缓存(ETag/Last-Modified) 1.2 缓存位置1.2.1 浏览器缓存1.2.2 代理服务器缓存 1.3 缓存策略选择1.3.1私有缓存1.3.2 公共资源缓存 1.4 V…...
高版本ant-design动态引用icon
需求 最近在更新自己的博客系统,从 vue2 升到 vue3,同步的也把 ant-design 从 1.7.8 跨越多个大版本升级到了 4.0.8,发现菜单上的 icon 报错了。 查询官方文档发现自从 2.0 版本以后的 icon 就不再支持通过 <a-icon /> 组件动态 type…...
【SQL】delete 与 truncate 命令的区别
区别 truncatedelete属于 DDL(数据定义语言) 范畴属于 DML(数据操作语言) 范畴删除表数据,不能删除视图数据删除表数据,删除视图数据只可以梭哈删除通过 where 进行选择性删除不涉及事务处理删除表中数据涉及事务处理效率高、但无法撤销效率低ÿ…...

【ITK库学习】使用itk库进行图像分割(四):水平集分割
目录 1、水平集2、itkFastMarchingImageFilter 快速步进分割3、itkShapeDetectionLevelSetImageFilter 快速步进分割 1、水平集 水平集是跟踪轮廓和表面运动的一种数字化方法。基于图像的亮度均值、梯度、边缘特征的微分计算,进行水平集分割。在itk中,所…...

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

深入剖析AI大模型:大模型时代的 Prompt 工程全解析
今天聊的内容,我认为是AI开发里面非常重要的内容。它在AI开发里无处不在,当你对 AI 助手说 "用李白的风格写一首关于人工智能的诗",或者让翻译模型 "将这段合同翻译成商务日语" 时,输入的这句话就是 Prompt。…...
Linux链表操作全解析
Linux C语言链表深度解析与实战技巧 一、链表基础概念与内核链表优势1.1 为什么使用链表?1.2 Linux 内核链表与用户态链表的区别 二、内核链表结构与宏解析常用宏/函数 三、内核链表的优点四、用户态链表示例五、双向循环链表在内核中的实现优势5.1 插入效率5.2 安全…...

label-studio的使用教程(导入本地路径)
文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...

从WWDC看苹果产品发展的规律
WWDC 是苹果公司一年一度面向全球开发者的盛会,其主题演讲展现了苹果在产品设计、技术路线、用户体验和生态系统构建上的核心理念与演进脉络。我们借助 ChatGPT Deep Research 工具,对过去十年 WWDC 主题演讲内容进行了系统化分析,形成了这份…...
模型参数、模型存储精度、参数与显存
模型参数量衡量单位 M:百万(Million) B:十亿(Billion) 1 B 1000 M 1B 1000M 1B1000M 参数存储精度 模型参数是固定的,但是一个参数所表示多少字节不一定,需要看这个参数以什么…...

【网络安全产品大调研系列】2. 体验漏洞扫描
前言 2023 年漏洞扫描服务市场规模预计为 3.06(十亿美元)。漏洞扫描服务市场行业预计将从 2024 年的 3.48(十亿美元)增长到 2032 年的 9.54(十亿美元)。预测期内漏洞扫描服务市场 CAGR(增长率&…...

云原生玩法三问:构建自定义开发环境
云原生玩法三问:构建自定义开发环境 引言 临时运维一个古董项目,无文档,无环境,无交接人,俗称三无。 运行设备的环境老,本地环境版本高,ssh不过去。正好最近对 腾讯出品的云原生 cnb 感兴趣&…...
scikit-learn机器学习
# 同时添加如下代码, 这样每次环境(kernel)启动的时候只要运行下方代码即可: # Also add the following code, # so that every time the environment (kernel) starts, # just run the following code: import sys sys.path.append(/home/aistudio/external-libraries)机…...
【Elasticsearch】Elasticsearch 在大数据生态圈的地位 实践经验
Elasticsearch 在大数据生态圈的地位 & 实践经验 1.Elasticsearch 的优势1.1 Elasticsearch 解决的核心问题1.1.1 传统方案的短板1.1.2 Elasticsearch 的解决方案 1.2 与大数据组件的对比优势1.3 关键优势技术支撑1.4 Elasticsearch 的竞品1.4.1 全文搜索领域1.4.2 日志分析…...
学习一下用鸿蒙DevEco Studio HarmonyOS5实现百度地图
在鸿蒙(HarmonyOS5)中集成百度地图,可以通过以下步骤和技术方案实现。结合鸿蒙的分布式能力和百度地图的API,可以构建跨设备的定位、导航和地图展示功能。 1. 鸿蒙环境准备 开发工具:下载安装 De…...