-
Notifications
You must be signed in to change notification settings - Fork 0
/
FlowLayout.kt
219 lines (159 loc) · 6.56 KB
/
FlowLayout.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
package com.example.jd.util
import android.content.Context
import android.graphics.Canvas
import android.util.AttributeSet
import android.util.Log
import android.view.View
import android.view.ViewGroup
import androidx.core.view.*
import java.util.*
/**
* author : Tiaw.
* date : 4/12/21
* 博客:https://blog.csdn.net/weixin_44819566
* desc : FlowLayout 流式布局
*/
class FlowLayout : ViewGroup {
//间隙
val space = 5
//每一行子View
var listView = ArrayList<List<View>>()
//每一行子View的高
var listLineHeight = ArrayList<Int>()
/**
* 用来new对象
*/
constructor(context: Context?) : super(context)
/**
* xml中执行
*/
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
/**
* style中属性调用
*/
constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(
context,
attrs,
defStyleAttr
)
/**
* 子控件获取marge方法
*/
override fun generateLayoutParams(p: LayoutParams?): LayoutParams? {
return MarginLayoutParams(p)
}
override fun generateLayoutParams(attrs: AttributeSet?): LayoutParams? {
return MarginLayoutParams(context, attrs)
}
override fun generateDefaultLayoutParams(): LayoutParams? {
return MarginLayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
listView = ArrayList()
listLineHeight = ArrayList()
//一行的宽和高
var lineWidth = 0
var lineHeight = 0
//父容器的宽和高
var parentWidth = 0;
var parentHeight = 0;
var views = ArrayList<View>()
val widthSize = MeasureSpec.getSize(widthMeasureSpec)
val heightSize = MeasureSpec.getSize(heightMeasureSpec)
//ViewGroup中所有子View
(0 until childCount).forEach {
//取出每个子View
val childView = getChildAt(it)
Log.i("childViewIt", "$it")
//子View在ViewGroup中的实际布局 强转为as MarginLayoutParams为了获取margin的高度
val layoutParams = childView.layoutParams as MarginLayoutParams
//子View 宽的MeauserSpec
val childWidthMeasureSpec = getChildMeasureSpec(
widthMeasureSpec, paddingLeft + paddingRight, layoutParams.width
)
val childHeightMeasureSpec = getChildMeasureSpec(
heightMeasureSpec, paddingBottom + paddingTop, layoutParams.height
)
childView.measure(childWidthMeasureSpec, childHeightMeasureSpec)
val childWidth = childView.measuredWidth + childView.marginLeft + childView.marginRight
val childHeight =
childView.measuredHeight + childView.marginTop + childView.marginBottom
//如果记录的宽+当前的宽 > ViewGroup的宽说明需要换行
if (lineWidth + childWidth > widthSize) {
//记录每一行子View的高
listLineHeight.add(lineHeight)
//记录每行View信息
listView.add(views)
//每当换行记录最大的宽和累加的高作为父容器的宽高
parentWidth = Math.max(lineWidth + space, parentWidth + space)
parentHeight += lineHeight + space
views = ArrayList()
lineWidth = 0;
lineHeight = 0;
}
//记录每一个子View
views.add(childView)
//记录当前的宽
lineWidth += childWidth + space
//取出一行中最高的作为当前的高
lineHeight = Math.max(lineHeight, childHeight + space)
Log.i("lineHeight", "$lineWidth $lineHeight")
//处理最后一个
if (it == childCount - 1) {
//记录每一行子View的高
listLineHeight.add(lineHeight)
//记录每行View信息
listView.add(views)
//每当换行记录最大的宽和累加的高作为父容器的宽高
parentWidth = Math.max(lineWidth, parentWidth + space)
parentHeight += lineHeight + space
}
}
val widthMode = MeasureSpec.getMode(widthMeasureSpec)
val heightMode = MeasureSpec.getMode(heightMeasureSpec)
Log.i(
"测量结果为1",
"${widthMode == MeasureSpec.EXACTLY} ${heightMode == MeasureSpec.EXACTLY}"
)
Log.i("测量结果为2", "$widthSize $heightSize")
Log.i("测量结果为3", "$parentWidth $parentHeight")
parentWidth += paddingLeft + paddingRight + marginLeft + marginRight
parentHeight += paddingTop + paddingBottom + marginTop + marginBottom
//测量最终结果
setMeasuredDimension(
if (widthMode == MeasureSpec.EXACTLY) widthSize else parentWidth,
if (heightMode == MeasureSpec.EXACTLY) heightSize else parentHeight
)
}
override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
Log.i("Layoutpadding", "$paddingLeft $paddingRight")
var padLeft = paddingLeft
var padTop = paddingTop
//循环每行View
for (index in (0 until listView.size)) {
val it = listView[index]
//每一行的高
val lineHeight = listLineHeight[index]
//循环每行View中的每个View
it.forEach {
// 获取margin
val marginLayoutParams = it.layoutParams as MarginLayoutParams
var left = padLeft + marginLayoutParams.leftMargin
val right = left + it.measuredWidth
val top = padTop + marginLayoutParams.topMargin
val bottom = top + it.measuredHeight
Log.i("View位置", "$index :$left $right $top $bottom")
it.layout(left, top, right, bottom)
//当循环第二个的时候,左侧间距为第一个的宽+间距 + 第一个右边的距离
padLeft = right + space + marginLayoutParams.rightMargin
}
//当循环第二行的时候 高度需要添加第一行的高度
padTop += lineHeight + space + marginBottom
padLeft = paddingLeft + marginRight
}
}
override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas)
}
}