class AutoArrangeLayout(context: Context, attrs: AttributeSet?) : ViewGroup(context, attrs) {
var horizontalSpacing: Int = 0
set(value) {
field = value
requestLayout()
}
var verticalSpacing: Int = 0
set(value) {
field = value
requestLayout()
}
init {
val ta = context.obtainStyledAttributes(attrs, R.styleable.AutoArrangeLayout)
horizontalSpacing = ta.getDimensionPixelSize(R.styleable.AutoArrangeLayout_horizontalSpacing, 20)
verticalSpacing = ta.getDimensionPixelSize(R.styleable.AutoArrangeLayout_verticalSpacing, 20)
ta.recycle()
}
override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
if (changed) {
(0..childCount)
.asSequence()
.map { getChildAt(it) }
.forEach {
it?.let {
val get = map[it]
if (get != null) {
it.layout(get.x, get.y, get.x + it.measuredWidth, get.y + it.measuredHeight)
}
}
}
}
}
var map: HashMap<View, Point> = HashMap()
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
var length = paddingLeft
var rowHeight = 0
var lastLineHeight = paddingTop + verticalSpacing
map.clear()
(0..childCount).
map { getChildAt(it) }
.forEach {
it?.let {
measureChild(it, widthMeasureSpec, heightMeasureSpec)
if (it.measuredWidth + length + horizontalSpacing + paddingLeft + paddingRight <= measuredWidth) {
val point = Point()
length += horizontalSpacing
point.x = length
point.y = lastLineHeight
map.put(it, point)
length += it.measuredWidth
rowHeight = Math.max(it.measuredHeight, rowHeight)
} else {
length = horizontalSpacing + paddingLeft
lastLineHeight += rowHeight + verticalSpacing
val point = Point()
point.x = length
point.y = lastLineHeight
map.put(it, point)
length += it.measuredWidth
rowHeight = it.measuredHeight
}
}
}
val heightMode = MeasureSpec.getMode(heightMeasureSpec)
var calcHeightMeasureSpec = heightMeasureSpec
if (heightMode == MeasureSpec.AT_MOST) {
calcHeightMeasureSpec = MeasureSpec.makeMeasureSpec(lastLineHeight + rowHeight + verticalSpacing, MeasureSpec.EXACTLY)
}
super.onMeasure(widthMeasureSpec, calcHeightMeasureSpec)
}
}
上述是自定义ViewGroup的类代码,是一个自动排列布局.
测试的时候在界面上还有个btn,点击一次会调用一次该类实例的addView方法,但是发现如果addView后,在该类的高设为wrap的情况下,如果高不足以新换一行则addView添加的视图不显示,若足够新换一行,则会连同之前添加的未显示的view一次性全部显示到界面上。