(原创)自定义控件:写一个瀑布流效果

news/2024/4/16 2:02:41

效果展示

最近要业务中需要做一个瀑布流的效果,按理说正常的瀑布流网上已经有很多解决方案了。
但我还是想自己尝试写一下。
又因为这块要求有一点特殊,下面大概讲下需求:
首先子元素的对方肯定还是和其他瀑布流一样,按照子View的宽高动态摆放位置
然后这边子View都是Textview,其实就是各种标签
还有就是要求可以限制行数
比如子元素很多,只展示前两行
后面的用“…”表示(类似我们TextView里面文字过多时展示的效果一样)
具体效果如下:
在这里插入图片描述
可以看到最后的一个标签的内容是省略号
如果规定是三行,并且每超出规定行数,效果是这样的(红色背景色是我自己加的):
在这里插入图片描述
那么开干

测量代码

这边先定义了两个变量:childMarginRight 和chilMarginBottom
主要是来控制子View之间的间距的
还有一个mMaxLines控制最大行数
这边思路是:动态测量子View,当超过两行时,把最后一个子View的内容改为省略号
先看测量方法:

  override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {val widthSize = MeasureSpec.getSize(widthMeasureSpec)val widthMode = MeasureSpec.getMode(widthMeasureSpec)val heightSize = MeasureSpec.getSize(heightMeasureSpec)val heightMode = MeasureSpec.getMode(heightMeasureSpec)val childCount = childCountvar lineWidth = 0var lineHeight = 0 //单行最大的高度var width = 0var height = 0 //总高度var lineCount = 1 // 当前行数for (i in 0 until childCount) {val child = getChildAt(i)measureChild(child, widthMeasureSpec, heightMeasureSpec)val childWidth = child.measuredWidth + childMarginRightval childHeight = child.measuredHeightif (lineWidth + childWidth > widthSize) { // 换行lineWidth = 0lineHeight = childHeightlineCount++ // 行数加1if (lineCount > mMaxLines) { // 超过最大行数,剩余的子控件不再计算在内lineCount = mMaxLinesbreak}height += lineHeight} else {//求出这行最大的高lineHeight = lineHeight.coerceAtLeast(childHeight)}lineWidth += childWidth}width = if (widthMode == MeasureSpec.EXACTLY) widthSize else lineWidthheight =if (heightMode == MeasureSpec.EXACTLY) heightSize else height + lineHeight + chilMarginBottom * (lineCount - 1)setMeasuredDimension(width, height)} 

可以看到,每次换行时都判断下是否超出行了
最后去动态设置每行的高度

换行问题

其实这里还有一个问题:
如果要超出规定行数时
是否可以不把最后一行的最后一个元素的文字内容改为…,
而是直接又添加一个内容为…的TextView
只不过如果这样实现,就要判断新添加的元素会不会导致换行
所以这边没那么麻烦,当判断出要换行后,直接把最后一行的最后一个元素的文字内容改为…,
这块逻辑在onlayout中实现,如下:

  override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {val width = widthval childCount = childCountvar lineHeight = 0 //当前行最高子View的高度var left = 0 //当前画到的left位置var top = 0 //当前画到的top位置var lineCount = 1 // 当前行数//这里是算出在行数固定的情况下,最多能塞进多少子ViewmaxChildCount = if (maxChildCount == -1) childCount else maxChildCountfor (i in 0 until maxChildCount) {val child = getChildAt(i)val childWidth = child.measuredWidthval childHeight = child.measuredHeightif (left + childWidth + childMarginRight > width) { // 换行left = 0top += lineHeight + chilMarginBottomlineHeight = childHeightlineCount++ // 行数加1if (lineCount > mMaxLines) { // 超过最大行数,剩余的子控件不再布局maxChildCount = iif (lastChildView != null && lastChildView is TextView) {//最后一个元素设为...,如果不是textview,也可以自己额外加逻辑post {(lastChildView as TextView).apply {text = "..."requestLayout()}}}break}}lastChildView = childif (left != 0 && left + childWidth + childMarginRight <= width) {//说明不是这行的第一个子View 并且 加上右边间距后不会超出这一行left += childMarginRight}child.layout(left, top, left + childWidth, top + childHeight)left += childWidth//记录这一行最高的高度lineHeight = lineHeight.coerceAtLeast(childHeight)}}

可以看到,超出规定行数的元素就不会再摆放进去了
同时要计算好间距各种

完整代码

最后贴下完整代码吧
这个控件比较简单,大家可以作为自定义控件的一个示例来学习

class XiongFlowLayout : ViewGroup {private var mMaxLines = 2 // 最大行数private var lastChildView: View? = null //布局里最后一个View,如果是超过两行并且这个View是Textview时修改文字为...private var maxChildCount = -1 //当前行数最大允许添加进布局的子View数量/*** 主要用来设置子View之间的间距的*/private var childMarginRight = 10private var chilMarginBottom = 10constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) {// 构造方法}/*** 设置View之间的间距*/fun setChildMargin(childMarginRight: Int, chilMarginBottom: Int) {this.childMarginRight = childMarginRightthis.chilMarginBottom = chilMarginBottomrequestLayout()}// 设置最大行数fun setMaxLines(maxLines: Int) {if (maxLines >= 1) {mMaxLines = maxLinesrequestLayout()}}override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {val widthSize = MeasureSpec.getSize(widthMeasureSpec)val widthMode = MeasureSpec.getMode(widthMeasureSpec)val heightSize = MeasureSpec.getSize(heightMeasureSpec)val heightMode = MeasureSpec.getMode(heightMeasureSpec)val childCount = childCountvar lineWidth = 0var lineHeight = 0 //单行最大的高度var width = 0var height = 0 //总高度var lineCount = 1 // 当前行数for (i in 0 until childCount) {val child = getChildAt(i)measureChild(child, widthMeasureSpec, heightMeasureSpec)val childWidth = child.measuredWidth + childMarginRightval childHeight = child.measuredHeightif (lineWidth + childWidth > widthSize) { // 换行lineWidth = 0lineHeight = childHeightlineCount++ // 行数加1if (lineCount > mMaxLines) { // 超过最大行数,剩余的子控件不再计算在内lineCount = mMaxLinesbreak}height += lineHeight} else {//求出这行最大的高lineHeight = lineHeight.coerceAtLeast(childHeight)}lineWidth += childWidth}width = if (widthMode == MeasureSpec.EXACTLY) widthSize else lineWidthheight =if (heightMode == MeasureSpec.EXACTLY) heightSize else height + lineHeight + chilMarginBottom * (lineCount - 1)setMeasuredDimension(width, height)}override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {val width = widthval childCount = childCountvar lineHeight = 0 //当前行最高子View的高度var left = 0 //当前画到的left位置var top = 0 //当前画到的top位置var lineCount = 1 // 当前行数//这里是算出在行数固定的情况下,最多能塞进多少子ViewmaxChildCount = if (maxChildCount == -1) childCount else maxChildCountfor (i in 0 until maxChildCount) {val child = getChildAt(i)val childWidth = child.measuredWidthval childHeight = child.measuredHeightif (left + childWidth + childMarginRight > width) { // 换行left = 0top += lineHeight + chilMarginBottomlineHeight = childHeightlineCount++ // 行数加1if (lineCount > mMaxLines) { // 超过最大行数,剩余的子控件不再布局maxChildCount = iif (lastChildView != null && lastChildView is TextView) {//最后一个元素设为...,如果不是textview,也可以自己额外加逻辑post {(lastChildView as TextView).apply {text = "..."requestLayout()}}}break}}lastChildView = childif (left != 0 && left + childWidth + childMarginRight <= width) {//说明不是这行的第一个子View 并且 加上右边间距后不会超出这一行left += childMarginRight}child.layout(left, top, left + childWidth, top + childHeight)left += childWidth//记录这一行最高的高度lineHeight = lineHeight.coerceAtLeast(childHeight)}}
}

http://www.ppmy.cn/news/370263.html

相关文章

电脑多久重装一次系统比较好

在长时间使用电脑后&#xff0c;一些用户可能会考虑重装系统来提升性能和稳定性。然而&#xff0c;电脑重装系统的频率是一个有争议的问题。本文将探讨电脑重装系统的最佳频率&#xff0c;以帮助您做出明智的决策。 工具/原料&#xff1a; 系统版本&#xff1a;win7旗舰版 品…

基于Vue3 + Element Plus 的后台管理系统详细教程

Vue3 概述 Vue.js 是一种轻量级MVVM框架&#xff0c;它通过双向绑定的方式&#xff0c;将视图与数据进行关联&#xff0c;简化了前端开发的流程。Vue3 是 Vue.js 的下一个版本&#xff0c;与早期版本相比&#xff0c;它具有更高的性能和更好的开发体验。 Composition API Vu…

【腾讯会议】本地录屏-转码-meeting_01.wemta

【腾讯会议】本地录屏-转码 腾讯会议中&#xff0c;录屏设置为本地录制&#xff0c; 完成后&#xff0c;是一堆这种文件&#xff1a; 怎么转换成mp4&#xff0c;可以播放呢&#xff1f; 原来在这里&#xff1a;找到历史会议记录&#xff0c; 点击打开&#xff0c;然后看到有个…

【腾讯会议】腾讯会议录屏

Win腾讯会议录屏 参考&#xff1a; https://www.zhihu.com/question/376601074/answer/1067611427 使用PC软件 Captura

报告视频录制:腾讯会议录屏+人像画中画特效

想录制PPT报告、软件操作&#xff0c;有什么免费的软件吗&#xff1f;腾讯会议即可&#xff0c;不仅完全免费&#xff0c;无时间限制&#xff0c;甚至支持人像实时扣图悬浮于桌面上(人像画中画)。 视频1. 录制全过程操作 https://v.qq.com/x/page/x3306hvqz4j.html 安装腾讯会议…

QQ语音和视频怎么在电脑上录制音频?

平时我们一般都会在手机上登陆QQ&#xff0c;但是在工作的时候也会在电脑上登陆&#xff0c;以免不能及时接收消息&#xff0c;对于在电脑上的语音聊天内容想录制下来需要怎么办呢&#xff1f; 方法/步骤&#xff1a; 1、在电脑上录制QQ语音内容&#xff0c;相当于在线录音&am…

uni-app 海康实时视频预览、录像回放、倍数回放、抓图、声音、录像、语言对讲、鱼眼 V2

地址&#xff1a;海康实时视频预览、录像回放、倍数回放、抓图、声音、录像、语言对讲、鱼眼 V2 - DCloud 插件市场 海康iSecure Center实时视频预览、录像回放、倍数回放、抓图、声音、录像、语言对讲、鱼眼 V2(ios、android) QQ群&#xff1a;928884722https://ext.dcloud.ne…

案例分享:Qt内窥镜相机录像程序(打开摄像头、支持多种摄像头、分辨率调整、翻转、旋转、亮度调整、拍照、录像、回放图片、回放录像)

若该文为原创文章&#xff0c;转载请注明原文出处 本文章博客地址&#xff1a;https://blog.csdn.net/qq21497936/article/details/108489004 长期持续项目技术分享&#xff0c;Shang业Ding制Zi询博主&#xff0c;QQ:21497936 WX:yangsir198808 红胖子(红模仿)的博文大全&#…

【qq视频录像机软件2013V3.0】聊天视频网络电视录像专家

qq视频录像机软件 2013 V3.0 [录制聊天视频,网络电视录像专家] 授权方式&#xff1a;免费软件 界面语言&#xff1a;简体中文 软件大小&#xff1a;10.40MB 所属专题&#xff1a;网络聊天 运行环境&#xff1a;Win2K,WinXP,Win2003,Vista,Win7 推荐星级&#xff1a; 发布时间…

从零开发一款相机APP 第九篇: Camera2相机 录像功能实现

【小驰笔记】【Android Camera开发】【Android Camera2】【camera2】 本课程内容由 小驰笔记 出品&#xff0c;欢迎关注&#xff0c;获取更多交流信息~ 欢迎访问个人博客&#xff1a;www.xiaochibiji.com我们先来看下MediaRecorder状态图&#xff1a; 一、正常录像 把mediaRe…

GB28181协议之设备录像查询

目录 一、概述 二、GB28181录像文件查询 2.1 录像文件基本要求 2.2 命令流程 2.3 抓包文件抓图示例 三、国标平台介绍 一、概述 近年来&#xff0c;国内视频监控应用发展迅猛&#xff0c;系统接入规模不断扩大&#xff0c;涌现了大量平台提供商&#xff0c;平台提供商的接…

腾讯会议发布录屏工具“会记”,让云端视频协作随用随录、随享随看

随着云端协同成为新常态&#xff0c;企业和组织沟通的形式也在不断丰富。1月5日&#xff0c;腾讯会议发布云端录屏工具“会记”&#xff0c; 用户在腾讯会议中就能自由使用人像、屏幕、声音、窗口等多种组合方式进行录制&#xff0c;录制完成后视频将自动上传至云端&#xff0c…

C#录制视频

这是一个使用C#语言制作的录制框架&#xff0c;支持录制桌面&#xff0c;多屏&#xff0c;声音&#xff0c;摄像头&#xff0c;某个应用程序的界面 1.安装 使用此框架需要安装扩展包Kogel.Record,可以Nuget上搜索 或者使用Nuget命令 Install-Package Kogel.Record 安装完成包后…

QQ怎么 发送 已经录好的视频

韩梦飞沙 韩亚飞 313134555qq.com yue31313 han_meng_fei_sha QQ发送 已经录好的视频 直接放过去&#xff0c;对方是需要下载的。 只有通过QQ录制的&#xff0c;才是直接就是自动下载播放的。 转载于:https://www.cnblogs.com/yue31313/p/7373733.html

C# AForge视频录像

原谅链接&#xff1a;https://www.yanning.wang/archives/424.html 一直觉得.net在多媒体处理方面渣得不行。最近需要做一个摄像头的程序&#xff0c;为了方便&#xff0c;用了AForge这个开源项目。AForge项目中有AForge.Video和AForge.Video. DirectShow这两个子项目&#xf…

腾讯会议怎么录屏

腾讯会议录屏如何使用&#xff0c;腾讯会议怎么录屏 腾讯会议录屏教程&#xff1a; 腾讯会议录屏的方法和步骤&#xff08;手机端&#xff09;&#xff1a; 1.在手机上打开腾讯会议开会界面&#xff0c;然后下拉选择手机自带的屏幕录制按钮。 2.就可以对腾讯会议进行录制了…

腾讯会议录制视频下载

背景解决方法 默认播放页面下全屏播放页面下 小总结 背景 最近在腾讯会议上参加了一场培训&#xff0c;我觉得特别棒&#xff0c;里面干货很多。老师使用了腾讯会议的云录制功能&#xff0c;然后把录制好的视频链接发给了我们。 如此优秀的培训课程&#xff0c;我想自己下载…

如何下载 qq群课堂 回放视频

如何下载 qq群课堂 回放视频 首先用电脑下载 fiddler4 然后安装 这个教程的视频演示见B站UP主 : 参考答案开心否 设置里面改这里 https 这样设置 开始下载QQ群回放的视频 打开后,先清除之前的 点击一个视频 看到这个host就是视频的下载地址了 右击选择保存为text 用文本文档打…

qq录制视频保存到哪了?qq录制视频怎么没了?找回方法在这

相信很多小伙伴都跟小编一样&#xff0c;使用qq录屏录制好后&#xff0c;结果就怎么也找不到录屏的文件了。经过小编一番研究&#xff0c;终于找到了qq录屏后视频文件的所保存的文件路径了。qq录制视频保存到哪了&#xff1f;别担心&#xff0c;下面小编就带大家一起来找找看。…

电脑录屏方法qq录屏

1.打开qq&#xff0c;任意选择一个好友对话框 2.ctrlalts&#xff0c;选择录屏工具 3.录屏结束后qq会自动弹出预览框&#xff0c;点击右下方的下载健保存至本地
最新文章