我有一个DialogFragment包含一个RecyclerView(卡片列表)。
DialogFragment
RecyclerView
其中RecyclerView有一个或多个CardViews可以具有任何高度。
CardViews
我想DialogFragment根据其中包含的内容给出正确的高度CardViews。
通常这很简单,我会这样设置wrap_content。RecyclerView
wrap_content
<android.support.v7.widget.RecyclerView ... xmlns:tools="http://schemas.android.com/tools" android:id="@+id/recycler_view" android:layout_width="match_parent" android:layout_height="wrap_content" android:clickable="true" android:scrollbars="vertical" > </android.support.v7.widget.RecyclerView>
因为我使用的是RecyclerView这不起作用:
https://issuetracker.google.com/issues/37001674
在这两个页面上,人们都建议扩展LinearLayoutManager和覆盖onMeasure()
LinearLayoutManager
onMeasure()
我首先使用了某人在第一个链接中提供的 LayoutManager :
public static class WrappingLayoutManager extends LinearLayoutManager { public WrappingLayoutManager(Context context) { super(context); } private int[] mMeasuredDimension = new int[2]; @Override public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state, int widthSpec, int heightSpec) { final int widthMode = View.MeasureSpec.getMode(widthSpec); final int heightMode = View.MeasureSpec.getMode(heightSpec); final int widthSize = View.MeasureSpec.getSize(widthSpec); final int heightSize = View.MeasureSpec.getSize(heightSpec); measureScrapChild(recycler, 0, View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), mMeasuredDimension); int width = mMeasuredDimension[0]; int height = mMeasuredDimension[1]; switch (widthMode) { case View.MeasureSpec.EXACTLY: case View.MeasureSpec.AT_MOST: width = widthSize; break; case View.MeasureSpec.UNSPECIFIED: } switch (heightMode) { case View.MeasureSpec.EXACTLY: case View.MeasureSpec.AT_MOST: height = heightSize; break; case View.MeasureSpec.UNSPECIFIED: } setMeasuredDimension(width, height); } private void measureScrapChild(RecyclerView.Recycler recycler, int position, int widthSpec, int heightSpec, int[] measuredDimension) { View view = recycler.getViewForPosition(position); if (view != null) { RecyclerView.LayoutParams p = (RecyclerView.LayoutParams) view.getLayoutParams(); int childWidthSpec = ViewGroup.getChildMeasureSpec(widthSpec, getPaddingLeft() + getPaddingRight(), p.width); int childHeightSpec = ViewGroup.getChildMeasureSpec(heightSpec, getPaddingTop() + getPaddingBottom(), p.height); view.measure(childWidthSpec, childHeightSpec); measuredDimension[0] = view.getMeasuredWidth(); measuredDimension[1] = view.getMeasuredHeight(); recycler.recycleView(view); } } }
然而 这并没有奏效 ,因为
heightSize = View.MeasureSpec.getSize(heightSpec);
返回一个看起来与 相关的非常大的值match_parent。
match_parent
通过评论 height = heightSize;(在第二个开关案例中),我设法使高度起作用,但前提是其中的TextView孩子CardView不包装自己的文本(长句)。
height = heightSize;
TextView
CardView
一旦TextView包裹它自己的文本,高度应该增加,但它不会。它将那个长句子的高度计算为单行,而不是换行(2 行或更多行)。
关于我应该如何改进这一点的任何建议,LayoutManager以便我RecyclerView可以使用WRAP_CONTENT?
LayoutManager
WRAP_CONTENT
编辑:这个布局管理器可能适用于大多数人,但它仍然存在滚动和计算包装文本视图高度的问题
public class MyLinearLayoutManager extends LinearLayoutManager { public MyLinearLayoutManager(Context context, int orientation, boolean reverseLayout) { super(context, orientation, reverseLayout); } private int[] mMeasuredDimension = new int[2]; @Override public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state, int widthSpec, int heightSpec) { final int widthMode = View.MeasureSpec.getMode(widthSpec); final int heightMode = View.MeasureSpec.getMode(heightSpec); final int widthSize = View.MeasureSpec.getSize(widthSpec); final int heightSize = View.MeasureSpec.getSize(heightSpec); int width = 0; int height = 0; for (int i = 0; i < getItemCount(); i++) { measureScrapChild(recycler, i, View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED), mMeasuredDimension); if (getOrientation() == HORIZONTAL) { width = width + mMeasuredDimension[0]; if (i == 0) { height = mMeasuredDimension[1]; } } else { height = height + mMeasuredDimension[1]; if (i == 0) { width = mMeasuredDimension[0]; } } } switch (widthMode) { case View.MeasureSpec.EXACTLY: width = widthSize; case View.MeasureSpec.AT_MOST: case View.MeasureSpec.UNSPECIFIED: } switch (heightMode) { case View.MeasureSpec.EXACTLY: height = heightSize; case View.MeasureSpec.AT_MOST: case View.MeasureSpec.UNSPECIFIED: } setMeasuredDimension(width, height); } private void measureScrapChild(RecyclerView.Recycler recycler, int position, int widthSpec, int heightSpec, int[] measuredDimension) { View view = recycler.getViewForPosition(position); if (view != null) { RecyclerView.LayoutParams p = (RecyclerView.LayoutParams) view.getLayoutParams(); int childWidthSpec = ViewGroup.getChildMeasureSpec(widthSpec, getPaddingLeft() + getPaddingRight(), p.width); int childHeightSpec = ViewGroup.getChildMeasureSpec(heightSpec, getPaddingTop() + getPaddingBottom(), p.height); view.measure(childWidthSpec, childHeightSpec); measuredDimension[0] = view.getMeasuredWidth() + p.leftMargin + p.rightMargin; measuredDimension[1] = view.getMeasuredHeight() + p.bottomMargin + p.topMargin; recycler.recycleView(view); } } }
从Android 支持库 23.2.1更新开始,所有 WRAP_CONTENT 都应该可以正常工作。
gradle请更新文件中的库版本 或 进一步:
gradle
compile 'com.android.support:recyclerview-v7:23.2.1'
解决了一些问题,例如 修复了与各种测量规范方法相关的错误
检查http://developer.android.com/tools/support- library/features.html#v7-recyclerview
您可以查看支持库修订历史