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 } }}

代码中注释已经写得很详细了,这里不再赘述,有不清楚的可以在评论区留言谈论,谢谢。

上一篇:Android - 动画
下一篇:Java中使用字符流读取UTF-8和写出txt文件 乱码 问题

发表评论

最新留言

路过按个爪印,很不错,赞一个!
[***.219.124.196]2025年04月17日 23时00分25秒