我正在写 custom 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
}
如果有人告诉我为什么会发生这种情况以及如何解决它,我会很高兴。
问题是在通话时
收到
View
的还没有测量。我用自定义方法做到了measureChildWithDecorationsAndMargin()
。因此,它没有尺寸。添加对标准方法的调用在打电话之前
getDecoratedMeasuredHeight(view)
解决了我的问题。