
Android - 流式布局(代码)
发布日期:2021-05-08 16:16:01
浏览次数:14
分类:精选文章
本文共 4844 字,大约阅读时间需要 16 分钟。
以前学的时候纯手写的流式布局(kotlin语言),肯定有很多的不足,比如代码太臃肿,基本没有封装等,但供学习使用还是不错的,话不多说,直接上代码:
import android.content.Contextimport android.util.AttributeSetimport android.util.Logimport android.view.Viewimport android.view.ViewGroupimport androidx.core.view.isEmptyclass FlowLayout:ViewGroup { constructor(context: Context):super(context){ } constructor(context: Context, attrs: AttributeSet?):super(context, attrs){ } //定义控件之间的间隔 private val space = 30 //定义所有的二维数组保存所有的View 方便等会儿layout var allViews: MutableList> = mutableListOf() //定义数组保存一排的View var everyLineViews: MutableList = mutableListOf() //定义一个数组保存每一行的最大高度,方便等会儿布局使用 private var allLineHeightList = mutableListOf () override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { /** * 由于onMeasure()方法的多次调用,多以要把这些变量定义在onMeasure()中,防止出错 */ //定义所有行中最长的长度(相当于父容器的宽带) var maxWidth = 0 //定义父容器的长度 var parentHeight = 0 //定义父容器的宽度 var parentWidth = 0 //定义一个变量记录当前行最大的高度 var currentWidth = space // 定义一个变量记录已经使用了多少宽度 var currentHeight = space //定义一个变量保存所有的高度(相当于父容器的高度) var totalHeight = 0 //重新初始化(由于变量定义在外部) allViews = mutableListOf() everyLineViews = mutableListOf() super.onMeasure(widthMeasureSpec, heightMeasureSpec) //获取父容器的最大宽高 val parentMaxWidth = MeasureSpec.getSize(widthMeasureSpec) Log.v("zj","父容器最大宽度:${ parentMaxWidth}") val parentMaxHeight = MeasureSpec.getSize(heightMeasureSpec)//不会用到,但还是写了 //确定子控件的measureSpec for(i in 0 until childCount){ var child = getChildAt(i) //得到每个子控件的布局参数 val lp = child.layoutParams //得到子控件的widthSpec var childWidthSpec = getChildMeasureSpec(widthMeasureSpec,2*space,lp.width) //得到子控件的heightSpec var childHeightSpec = getChildMeasureSpec(heightMeasureSpec,2*space,lp.height) //测量每个子控件 child.measure(childWidthSpec,childHeightSpec) /** * 流式布局最核心的算法 */ //在这一行添加 if(currentWidth+space+child.measuredWidth <= parentMaxWidth){ currentWidth+=child.measuredWidth+space currentHeight = Math.max(currentHeight,(child.measuredHeight+space)) }else{ //换到下一行 //将上一行的添加到保存所有View的数组中 allViews.add(everyLineViews) //重置上每一行的数组 但是不能用清空 ,必须重新分配内存(由于指针问题) everyLineViews = mutableListOf() //将上一行的高度加到总的高度里面 totalHeight+=currentHeight //将上一行的最大高度存到数组中 allLineHeightList.add(currentHeight) maxWidth = Math.max(maxWidth,currentWidth) //进行下一行的初始化 currentHeight = child.measuredHeight+space currentWidth = child.measuredWidth+space } //添加孩子到数组中 everyLineViews.add(child) } //判断是否还有不满一行的控件没有被计算到 if(everyLineViews.size!=0){ currentWidth = 0 currentHeight = 0 for (i in 0 until everyLineViews.size){ //得到每个子控件 val child = everyLineViews[i] //这个bug时候来修改过来的,解决最后一行高低总是不对的问题;错误版本是child = getChild(i) //当前宽度等于余下的每个子控件的宽度加总 再加上 space间隔 currentWidth += child.measuredWidth+space //当前这一行的高度就是这一个控件的高度+space与上一次保存的最大行高相比,谁大取谁 currentHeight = Math.max(currentHeight,child.measuredHeight+space) } //余下的这一行的总宽度再与前面的n行的最长的比较,谁大取谁 maxWidth = Math.max(maxWidth,currentWidth) //算出总的高度 totalHeight+=currentHeight allLineHeightList.add(currentHeight) //将这一行添加到数组中 allViews.add(everyLineViews) } //设置父容器的最终尺寸 parentHeight = totalHeight+space parentWidth = maxWidth+space setMeasuredDimension(parentWidth,parentHeight) } override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) { var left = space var top = space var right = 0 var bottom = 0 Log.v("aa","子控件的个数:${ childCount}") Log.v(("aa"),"添加所有视图有几行:${ allViews.size}") for (i in 0 until allViews.size){ //得到每一行的控件 //进入第一行的布局 for(j in 0 until allViews[i].size){ //得到每一行中的每个控件 val child = allViews[i][j] right = left+child.measuredWidth bottom = top + child.measuredHeight child.layout(left,top,right,bottom) left+=child.measuredWidth+space } //计算下一行的相关位置 top += allLineHeightList[i] left = space } }}
代码中注释已经写得很详细了,这里不再赘述,有不清楚的可以在评论区留言谈论,谢谢。
发表评论
最新留言
路过按个爪印,很不错,赞一个!
[***.219.124.196]2025年04月17日 23时00分25秒
关于作者

喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
【计算机网络】应用层
2021-05-09
【Maven】POM基本概念
2021-05-09
【Java思考】Java 中的实参与形参之间的传递到底是值传递还是引用传递呢?
2021-05-09
【设计模式】单例模式
2021-05-09
【SpringCloud】Hystrix熔断器
2021-05-09
【Linux】2.3 Linux目录结构
2021-05-09
java.util.Optional学习笔记
2021-05-09
远程触发Jenkins的Pipeline任务的并发问题处理
2021-05-09
CoProcessFunction实战三部曲之二:状态处理
2021-05-09
jackson学习之七:常用Field注解
2021-05-09
jackson学习之八:常用方法注解
2021-05-09
Web应用程序并发问题处理的一点小经验
2021-05-09
asp.net core的授权过滤器中获取action上的Attribute
2021-05-09
entity framework core在独立类库下执行迁移操作
2021-05-09
Asp.Net Core 2.1+的视图缓存(响应缓存)
2021-05-09
服务器开发- Asp.Net Core中的websocket,并封装一个简单的中间件
2021-05-09
没花一分钱的我竟然收到的JetBrains IDEA官方免费赠送一年的Licence
2021-05-09
Redis 集合统计(HyperLogLog)
2021-05-09
RE套路 - 关于pyinstaller打包文件的复原
2021-05-09
【wp】HWS计划2021硬件安全冬令营线上选拔赛
2021-05-09