View Group не отображает дочерние view на маленьком экране
Реализовал собственный FlexBoxLayout, работает адекватно, но как только высота устройства становится маленькой, дочерние элементы ViewGroup перестают отрисовываться.
Код flexBoxLayout
class EmojiReactionFlexBoxLayout @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0, defStyleRes: Int = 0
) : ViewGroup(context, attrs, defStyleAttr) {
private var spaceBetweenHorizontal = 0f
set(value) {
field = value
requestLayout()
}
private var spaceBetweenVertical = 0f
set(value) {
field = value
requestLayout()
}
init {
val typedArray = context.obtainStyledAttributes(
attrs,
R.styleable.EmojiReactionFlexBoxLayout,
defStyleAttr,
defStyleRes
)
spaceBetweenHorizontal =
typedArray.getDimension(
R.styleable.EmojiReactionFlexBoxLayout_erfb_space_between_horizontal,
0F
)
spaceBetweenVertical =
typedArray.getDimension(
R.styleable.EmojiReactionFlexBoxLayout_erfb_space_between_vertical,
0F
)
typedArray.recycle()
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
var totalWidth = 0
var totalHeight = 0
val widthSize = MeasureSpec.getSize(widthMeasureSpec)
for (i in 0 until childCount) {
val child = getChildAt(i)
measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, totalWidth)
totalHeight = maxOf(totalHeight, child.measuredHeight)
totalWidth += child.measuredWidth + spaceBetweenHorizontal.toInt()
}
val maxChildHeight: Int = totalHeight
var countStrings: Int = ceil(totalWidth.toFloat() / widthSize.toFloat()).toInt()
while (countStrings > 1) {
countStrings--
totalHeight += maxChildHeight + spaceBetweenVertical.toInt()
}
val resultWidth = resolveSize(totalWidth, widthMeasureSpec)
val resultHeight = resolveSize(totalHeight, heightMeasureSpec)
setMeasuredDimension(resultWidth, resultHeight)
}
override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
var currentRight = 0
var currentTop = 0
for (i in 0 until childCount) {
val child = getChildAt(i)
if (currentRight + child.measuredWidth > measuredWidth) {
currentTop += child.measuredHeight + spaceBetweenVertical.toInt()
currentRight = 0
}
child.layout(
currentRight,
currentTop,
currentRight + child.measuredWidth,
currentTop + child.measuredHeight
)
currentRight = child.right + spaceBetweenHorizontal.toInt()
}
}
override fun generateLayoutParams(attrs: AttributeSet?): LayoutParams {
return MarginLayoutParams(context, attrs)
}
override fun checkLayoutParams(p: LayoutParams): Boolean {
return p is MarginLayoutParams
}
override fun generateLayoutParams(p: LayoutParams): LayoutParams {
return MarginLayoutParams(p)
}
}
Код child элемента
open class EmojiReactionButton @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0, defStyleRes: Int = 0
) : View(context, attrs, defStyleAttr) {
private var countReactions = ""
set(value) {
field = value
requestLayout()
}
private var emoji = ""
set(value) {
field = value
requestLayout()
}
private val textPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
textSize = resources.getDimension(R.dimen.simple_text)
textAlign = Paint.Align.CENTER
color = Color.RED
}
private val viewRect = Rect()
private val textCoordinate = PointF()
private val tempFontMetrics = Paint.FontMetrics()
init {
val typedArray = context.obtainStyledAttributes(
attrs,
R.styleable.EmojiReactionButton,
defStyleAttr,
defStyleRes
)
countReactions =
typedArray.getString(R.styleable.EmojiReactionButton_erb_count_reactions).orEmpty()
emoji =
typedArray.getString(R.styleable.EmojiReactionButton_erb_emoji).orEmpty()
textPaint.color =
typedArray.getColor(R.styleable.EmojiReactionButton_erb_color, Color.WHITE)
textPaint.textSize = typedArray.getDimension(
R.styleable.EmojiReactionButton_erb_text_size,
resources.getDimension(R.dimen.simple_text)
)
typedArray.recycle()
}
override fun setOnClickListener(l: OnClickListener?) {
super.setOnClickListener(l)
isSelected = !isSelected
if (!isSelected) {
setTextColor(Color.WHITE)
} else {
setTextColor(Color.GRAY)
}
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
textPaint.getTextBounds(
"$countReactions $emoji",
0,
"$countReactions $emoji".length,
viewRect
)
val totalHeight = viewRect.height() + paddingTop + paddingBottom
val totalWidth = viewRect.width() + paddingRight + paddingLeft
val resultWidth = resolveSize(totalWidth, widthMeasureSpec)
val resultHeight = resolveSize(totalHeight, heightMeasureSpec)
setMeasuredDimension(resultWidth, resultHeight)
}
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
textPaint.getFontMetrics(tempFontMetrics)
textCoordinate.x = w / 2f
textCoordinate.y = h / 2f + viewRect.height() / 2 - tempFontMetrics.descent
}
override fun onCreateDrawableState(extraSpace: Int): IntArray {
val drawableState = super.onCreateDrawableState(extraSpace + EXTRA_SUPPORTED_DRAWABLE_STATE.size)
if (isSelected) {
mergeDrawableStates(drawableState, EXTRA_SUPPORTED_DRAWABLE_STATE)
}
return drawableState
}
fun setTextColor(color: Int) {
textPaint.color = color
invalidate()
}
override fun onDraw(canvas: Canvas) {
canvas.drawText("$emoji $countReactions", textCoordinate.x, textCoordinate.y, textPaint)
}
companion object {
private val EXTRA_SUPPORTED_DRAWABLE_STATE = intArrayOf(android.R.attr.state_selected)
}
}
Ответы (1 шт):
Автор решения: MadBo
→ Ссылка
Проблема заключалась в том, что в методе onMeasure я использовал measureChildWithMargins, а не measureChild.

