LayoutManage: getDecoratedMeasuredHeight(view) всегда возвращает 0

Пишу кастомный LayoutManager. Есть вот такой метод

override fun onLayoutChildren(recycler: RecyclerView.Recycler, state: RecyclerView.State) {
        detachAndScrapAttachedViews(recycler)
        fillRecycler(state, recycler)
    }

private fun fillRecycler(
        state: RecyclerView.State,
        recycler: RecyclerView.Recycler
    ) {
        for (position in 0 until state.itemCount) {
            val spanInfo = spanProvider.getSpanOnPosition(position)
            val coordinates = matrix.add(Matrix.Point(spanInfo.column, spanInfo.row))

            val view: View = recycler.getViewForPosition(position)

            val cellWidth = (width - paddingStart - paddingEnd) / spanCount
            val cellHeight = if (isSquareCell) cellWidth
                             else getDecoratedMeasuredHeight(view) //todo вот здесь всегда 0

            val top = paddingTop + cellHeight * coordinates.top
            val bottom = paddingBottom + cellHeight * coordinates.bottom
            val left = paddingLeft + cellWidth * coordinates.left
            val right = paddingRight + cellWidth * coordinates.right

            measureChildWithDecorationsAndMargin(view, right - left, bottom - top)

            addView(view, position)
            layoutDecorated(view, left, top, right, bottom)
            checkLowestView(view, bottom, right)
        }
    }

Проблема заключается в том, что метод getDecoratedMeasuredHeight(view) всегда возвращает 0. Пробовал открыть саму View и получить оттуда LayoutParams там так же высота 0. Причем getDecoratedMeasuredWidth(view) возвращает корректное значение.

Вот собственно сам макет:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/spanItem"
    android:padding="16dp"
    android:layout_gravity="center"
    android:layout_width="200dp"
    android:layout_height="200dp">

    <TextView
        android:background="@android:color/transparent"
        android:id="@+id/textView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:textSize="22sp"
        tools:text="Test" />
</FrameLayout>

Вот метод generateDefaultLayoutParams():

override fun generateDefaultLayoutParams(): RecyclerView.LayoutParams =
        RecyclerView.LayoutParams(
            RecyclerView.LayoutParams.WRAP_CONTENT,
            RecyclerView.LayoutParams.WRAP_CONTENT
        )

Эти два метода для измерения детей View:

private fun measureChildWithDecorationsAndMargin(
        child: View,
        cellWidth: Int,
        cellHeight: Int
    ) {
        var widthSpec = View.MeasureSpec.makeMeasureSpec(cellWidth, View.MeasureSpec.EXACTLY)
        var heightSpec = View.MeasureSpec.makeMeasureSpec(cellHeight, View.MeasureSpec.EXACTLY)

        val decorRect = Rect()
        calculateItemDecorationsForChild(child, decorRect)
        val params = child.layoutParams as RecyclerView.LayoutParams
        widthSpec = updateSpecWithExtra(
            widthSpec, params.leftMargin + decorRect.left,
            params.rightMargin + decorRect.right
        )
        heightSpec = updateSpecWithExtra(
            heightSpec, params.topMargin + decorRect.top,
            params.bottomMargin + decorRect.bottom
        )
        child.measure(widthSpec, heightSpec)
    }

    private fun updateSpecWithExtra(spec: Int, startInset: Int, endInset: Int): Int {
        if (startInset == 0 && endInset == 0) return spec

        val mode = View.MeasureSpec.getMode(spec)
        return if (mode == View.MeasureSpec.AT_MOST || mode == View.MeasureSpec.EXACTLY) {
            View.MeasureSpec.makeMeasureSpec(View.MeasureSpec.getSize(spec) - startInset - endInset, mode)
        } else spec
    }

Если кто подскажет почему это происходит и как это можно решить буду очень рад.


Ответы (1 шт):

Автор решения: Sergei Buvaka

Проблема была в том, что к моменту вызова

getDecoratedMeasuredHeight(view)

полученная View не была еще измерена т.к. я это делал в кастомном методе measureChildWithDecorationsAndMargin(). Соответственно она не имела размеров. Добавление вызова стандартного метода

 measureChildWithMargins(view, 0, 0)

Перед вызовом getDecoratedMeasuredHeight(view) решило мою проблему.

→ Ссылка