源码
package com.community.mobile.widget
import android.content.Context
import android.util.AttributeSet
import android.view.Gravity
import android.view.View
import android.view.View.OnClickListener
import android.view.ViewGroup
import android.widget.Button
import android.widget.TextView
import com.safframework.log.L
class WrapLayout : ViewGroup {
var TEXTVIEW_STYLE = 0
var BUTTON_STYLE = 1
private var style = 0
private var btn: View? = null
constructor(context: Context?) : super(context) {}
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) {}
constructor(context: Context?, attrs: AttributeSet?, defStyle: Int) : super(
context,
attrs,
defStyle
) {
}
fun setData(
data: Array<String?>?,
context: Context,
textSize: Int,
pl: Int,
pt: Int,
pr: Int,
pb: Int,
ml: Int,
mt: Int,
mr: Int,
mb: Int
) {
createChild(data, context, textSize, pl, pt, pr, pb, ml, mt, mr, mb)
}
fun setData(
data: List<String?>?,
context: Context,
textSize: Int,
pl: Int,
pt: Int,
pr: Int,
pb: Int,
ml: Int,
mt: Int,
mr: Int,
mb: Int
) {
var mydata: Array<String?>? = null
if (data != null) {
val length = data.size
mydata = arrayOfNulls(length)
for (i in 0 until length) {
mydata[i] = data[i]
}
}
setData(mydata, context, textSize, pl, pt, pr, pb, ml, mt, mr, mb)
}
fun setView(textView : TextView){
this.addView(textView)
}
private fun createChild(
data: Array<String?>?,
context: Context,
textSize: Int,
pl: Int,
pt: Int,
pr: Int,
pb: Int,
ml: Int,
mt: Int,
mr: Int,
mb: Int
) {
val size = data!!.size
for (i in 0 until size) {
val text = data[i]
if (style == TEXTVIEW_STYLE) {
btn = TextView(context)
(btn as TextView).gravity = Gravity.CENTER
(btn as TextView).text = text
(btn as TextView).textSize = textSize.toFloat()
} else if (style == BUTTON_STYLE) {
btn = Button(context)
(btn as Button).setGravity(Gravity.CENTER)
(btn as Button).setText(text)
(btn as Button).setTextSize(textSize.toFloat())
}
btn?.setClickable(true)
btn?.setPadding(
dip2px(context, pl.toFloat()),
dip2px(context, pt.toFloat()),
dip2px(context, pr.toFloat()),
dip2px(context, pb.toFloat())
)
val params =
MarginLayoutParams(MarginLayoutParams.WRAP_CONTENT, MarginLayoutParams.WRAP_CONTENT)
params.setMargins(ml, mt, mr, mb)
btn?.setLayoutParams(params)
btn?.setOnClickListener(OnClickListener { markClickListener!!.clickMark(i) })
this.addView(btn)
}
}
private var markClickListener: MarkClickListener? = null
fun setMarkClickListener(markClickListener: MarkClickListener?) {
this.markClickListener = markClickListener
}
interface MarkClickListener {
fun clickMark(position: Int)
}
private fun dip2px(context: Context, dpValue: Float): Int {
val scale: Float = context.getResources().getDisplayMetrics().density
return (dpValue * scale + 0.5f).toInt()
}
override fun generateLayoutParams(attrs: AttributeSet?): LayoutParams {
return MarginLayoutParams(context, attrs)
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
val widthMode = MeasureSpec.getMode(widthMeasureSpec)
val heightMode = MeasureSpec.getMode(heightMeasureSpec)
val widthSize = MeasureSpec.getSize(widthMeasureSpec)
val heightSize = MeasureSpec.getSize(heightMeasureSpec)
val childCount = childCount
var lineWidth = 0
var lineHeight = 0
var width = 0
var height = 0
for (i in 0 until childCount) {
val child: View = getChildAt(i)
measureChild(child, widthMeasureSpec, heightMeasureSpec)
val lp = child.layoutParams as MarginLayoutParams
val childWidth: Int = child.measuredWidth + lp.leftMargin + lp.rightMargin
val childHeight: Int = child.measuredHeight + lp.topMargin + lp.bottomMargin
if (lineWidth + childWidth > widthSize) {
width = Math.max(lineWidth, childWidth)
lineWidth = childWidth
lineHeight = childHeight
height += lineHeight
} else {
lineWidth += childWidth
lineHeight = Math.max(height, childHeight)
}
if (i == childCount - 1) {
width = Math.max(width, lineWidth)
height += childHeight
}
}
L.i("lineHeight","${lineHeight}")
L.i("height","${height}")
setMeasuredDimension(
if (widthMode == MeasureSpec.EXACTLY) widthSize else width,
if (heightMode == MeasureSpec.EXACTLY) heightSize else height
)
}
private val mAllViews: MutableList<MutableList<View>> = ArrayList<MutableList<View>>()
private val mLineHeight: MutableList<Int> = ArrayList()
override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
mAllViews.clear()
mLineHeight.clear()
val width = width
val childCount = childCount
var lineViews: MutableList<View> = ArrayList<View>()
var lineWidth = 0
var lineHeight = 0
run {
var i = 0
while (i < childCount) {
val child: View = getChildAt(i)
val lp = child.getLayoutParams() as MarginLayoutParams
val childWidth: Int = child.getMeasuredWidth()
val childHeight: Int = child.getMeasuredHeight()
if (i == 3) {
i = 3
}
if (childWidth + lp.leftMargin + lp.rightMargin + lineWidth > width)
{
mLineHeight.add(lineHeight)
mAllViews.add(lineViews)
lineWidth = 0
lineViews = ArrayList<View>()
}
lineWidth += childWidth + lp.leftMargin + lp.rightMargin
lineHeight = Math.max(
lineHeight, childHeight + lp.topMargin
+ lp.bottomMargin
)
lineViews.add(child)
i++
}
}
mLineHeight.add(lineHeight)
mAllViews.add(lineViews)
var left = 0
var top = 0
val lineNums = mAllViews.size
for (i in 0 until lineNums) {
lineViews = mAllViews[i]
lineHeight = (i + 1) * mLineHeight[i]
for (j in lineViews.indices) {
val lineChild: View = lineViews[j]
if (lineChild.getVisibility() === View.GONE) {
continue
}
val lp = lineChild.getLayoutParams() as MarginLayoutParams
val lc = left + lp.leftMargin
val tc = top + lp.topMargin
val rc: Int = lc + lineChild.getMeasuredWidth()
val bc: Int = tc + lineChild.getMeasuredHeight()
lineChild.layout(lc, tc, rc, bc)
left += lineChild.getMeasuredWidth() + lp.rightMargin + lp.leftMargin
}
left = 0
top = lineHeight
}
}
fun setStyle(style: Int) {
this.style = style
}
companion object {
private const val TAG = "WrapLayout"
}
}
布局
<com.community.mobile.widget.WrapLayout
android:id="@+id/layout_wrap"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="6dp"
android:layout_marginEnd="10dp"
/>
数据渲染
private val oldIdentitysList = ArrayList<String>()
Handler().post {
binding.layoutWrap.removeAllViews()
identitysList.forEach {
val textView = TextView(context)
textView.setTextColor(context!!.resources.getColor(R.color.colorPrimary))
textView.textSize = 12f
textView.setBackgroundResource(R.drawable.shape_tab_identity_in_user_center)
textView.text = it.replace("\n", "").trim()
textView.tag = textView.text
textView.setPadding(15, 5, 15, 5)
val params =
ViewGroup.MarginLayoutParams(
ViewGroup.MarginLayoutParams.WRAP_CONTENT,
ViewGroup.MarginLayoutParams.WRAP_CONTENT
)
params.setMargins(5, 5, 5, 5)
textView.layoutParams = params
binding.layoutWrap.setView(textView)
}
}
最终效果
