倒霉的菜鸟

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理
  1 class WaterFlowLayout constructor(context: Context, attrs: AttributeSet) : ViewGroup(context, attrs) {
  2 
  3     override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
  4         //定义子view的初始位置为parent传入的初始位置
  5         var left: Int
  6         var right: Int
  7         var top: Int
  8         var bottom: Int
  9         //开始遍历
 10         //当前行高
 11         var currentHeight = 0
 12         list.forEachIndexed { index, arrayList ->
 13 
 14             var currentWidth = 0
 15             arrayList.forEach {
 16                 val marginLayoutParams = it.layoutParams as MarginLayoutParams
 17                 top = t + currentHeight + marginLayoutParams.topMargin
 18                 left = l + currentWidth + marginLayoutParams.leftMargin
 19                 right = left + it.layoutParams.width + marginLayoutParams.rightMargin
 20                 bottom = top + it.layoutParams.height + marginLayoutParams.bottomMargin
 21                 currentWidth = right
 22                 it.layout(left, top, right,bottom)
 23             }
 24             currentHeight += heightList.get(index)
 25         }
 26     }
 27 
 28     override fun generateLayoutParams(attrs: AttributeSet?): LayoutParams {
 29         return MarginLayoutParams(context, attrs)
 30     }
 31 
 32     /**
 33      * 因为onLayout时需要遍历各个子view确定他们的位置
 34      * 所以我们需要一个list来保存各个子view
 35      * list的每个元素表示一行
 36      */
 37     private var list = arrayListOf<ArrayList<View>>()
 38 
 39     /**
 40      * 同样为了onLayout时确定每一行的行高
 41      * 我们再加一个List保存行高信息
 42      */
 43     private var heightList = arrayListOf<Int>()
 44 
 45     /**
 46      * 通过源码我们知道  这里传进来的时parent的约束信息
 47      */
 48     override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
 49         //因为onMeasure方法会调用两次  所以需要clear
 50         list.clear()
 51         heightList.clear()
 52         //根据传进来的参数,获取父容器的宽高
 53         val parentWidth = MeasureSpec.getSize(widthMeasureSpec)
 54         val parentHeight = MeasureSpec.getSize(heightMeasureSpec)
 55 
 56         //定义变量记录最终测量出的宽高信息
 57         var measureWidth = 0
 58         var measureHeight = 0
 59         //获取父容器传进来的Mode信息
 60         val widthMode = MeasureSpec.getMode(widthMeasureSpec)
 61         val heightMode = MeasureSpec.getMode(heightMeasureSpec)
 62         //如果Mode是match_parent, 那么直接返回父容器的宽高
 63         if (widthMode == MeasureSpec.EXACTLY && heightMode == MeasureSpec.EXACTLY){
 64             measureWidth = parentWidth
 65             measureHeight = parentHeight
 66         }else{
 67             //如果不是EXACTLY,就需要计算宽高
 68 
 69             //定义当前行宽,高
 70             var currentWidth = 0
 71             var currentHeight = 0
 72 
 73             //定义一个list保存当前行里的child
 74             var childList = arrayListOf<View>()
 75             //遍历childs
 76             children.forEach {
 77                 val marginLayoutParams = it.layoutParams as MarginLayoutParams
 78                 //每个元素的宽等于它本身的宽加左右Margin
 79                 val childWidth = it.layoutParams.width + marginLayoutParams.leftMargin + marginLayoutParams.rightMargin
 80                 //每个元素的高等于它本身的高加上下Margin
 81                 val childHeight =  it.layoutParams.height +marginLayoutParams.topMargin + marginLayoutParams.bottomMargin
 82 
 83                 //如果当前已有行宽+该子view行宽已经大于父容器给定的行宽, 则需要换行
 84                 if (currentWidth + childWidth > parentWidth){
 85                     //换行
 86                     //保存上一行的行高
 87                     heightList.add(currentHeight)
 88 
 89                     //换行后,新行宽度就等于子View的宽度
 90                     currentWidth = childWidth
 91                     //新行高度等于子View的高度
 92                     currentHeight = childHeight
 93                     //最终测量出来的宽度为各行的最大宽度
 94                     measureWidth = Math.max(currentWidth, measureWidth)
 95                     //最终测量出来的高度为各行高度累加
 96                     measureHeight += currentHeight
 97 
 98                     //换行的话, 先把原本的当前行加到list中
 99                     list.add(childList)
100 
101                     //再把childlist置空,放入新的childView
102                     childList = arrayListOf(it)
103 
104                 }else {
105                     //否则, 将该子view放在当前行
106                     currentWidth +=childWidth
107                     //高度取已有行高和当前子view高度之间的最大值
108                     currentHeight = Math.max(currentHeight, childHeight)
109                     //最终测量出来的宽度为各行的最大宽度
110                     measureWidth = Math.max(currentWidth, measureWidth)
111 
112                     //将这个子view放在当前行
113                     childList.add(it)
114                 }
115             }
116             //for循环执行完之后,将最后一个当前行加入到list
117             Log.d("-----", "end child list size:"+childList.size )
118             list.add(childList)
119             measureHeight += currentHeight
120             heightList.add(currentHeight)
121         }
122         //必须set, 否则会抛出IllegalStateException
123         setMeasuredDimension(measureWidth, measureHeight)
124     }
125 }

 

posted on 2021-10-13 22:40  倒霉的菜鸟  阅读(36)  评论(0编辑  收藏  举报