将RecyclerView的宽高属性设置为“wrap_content”
2016-04-14 16:56
666 查看
前言
最近,在使用RecyclerView时遇到一个问题,就是将RecyclerView的高度设置为“wrap_content”时,控件实际测量高度为”match_parent”,为什么会出现这种问题呢?RecyclerView设置如下:<android.support.v7.widget.RecyclerView android:id="@+id/sv_rv" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@android:color/darker_gray"> </android.support.v7.widget.RecyclerView>
recyclerView = (RecyclerView)findViewById(R.id.sv_rv); recyclerView.setLayoutManager(new LinearLayoutManager(getApplicationContext())); recyclerView.setAdapter(new RvAdapter());
而实际显示效果如下:
正文
一般来说,出现这种问题是因为高度测量问题,所以先查看RecyclerView的onMeasure方法,如下:@Override protected void onMeasure(int widthSpec, int heightSpec) { if (mAdapterUpdateDuringMeasure) { eatRequestLayout(); processAdapterUpdatesAndSetAnimationFlags(); if (mState.mRunPredictiveAnimations) { // TODO: try to provide a better approach. // When RV decides to run predictive animations, we need to measure in pre-layout // state so that pre-layout pass results in correct layout. // On the other hand, this will prevent the layout manager from resizing properly. mState.mInPreLayout = true; } else { // consume remaining updates to provide a consistent state with the layout pass. mAdapterHelper.consumeUpdatesInOnePass(); mState.mInPreLayout = false; } mAdapterUpdateDuringMeasure = false; resumeRequestLayout(false); } if (mAdapter != null) { mState.mItemCount = mAdapter.getItemCount(); } else { mState.mItemCount = 0; } if (mLayout == null) { defaultOnMeasure(widthSpec, heightSpec); } else { mLayout.onMeasure(mRecycler, mState, widthSpec, heightSpec); } mState.mInPreLayout = false; // clear }
重要代码:
if (mLayout == null) { defaultOnMeasure(widthSpec, heightSpec); } else { mLayout.onMeasure(mRecycler, mState, widthSpec, heightSpec); } }
可以发现当RecyclerView设置LayoutManager时,RecyclerView的测量高度由所选择的LayoutManager决定。由于上文所选择的LayoutManager为LinearLayoutManager,故查看其源码的onMeasure函数,然而并没找到,那就查看其父类的onMeasure函数。
public void onMeasure(Recycler recycler, State state, int widthSpec, int heightSpec) { mRecyclerView.defaultOnMeasure(widthSpec, heightSpec); }
然后查看defaultOnMeasure函数,可以发现其并未对子item进行高度测量,所以导致其实测高度异常。故而要纠正此问题,需要重写LayoutManager的onMeasure函数。
如下,是我自己写的一个简单的LayoutManager子类,继承自LinearLayoutManager,仅作抛砖引玉之用:
package how.th.ridelib.RvLayoutManager; import android.content.Context; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.View; public class RecyclerLayoutManager extends LinearLayoutManager { public RecyclerLayoutManager(Context context){ super(context); } @Override public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state, int widthSpec, int heightSpec) { int itemCount = state.getItemCount(); int measuredWidth = 0; int measuredHeight = 0; int heightSize = View.MeasureSpec.getSize(heightSpec); for(int i = 0; i < itemCount; i ++){ View view = recycler.getViewForPosition(i); if(view != null){ RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams)view.getLayoutParams(); int margin = layoutParams.bottomMargin + layoutParams.topMargin; measuredWidth = View.MeasureSpec.getSize(widthSpec); view.measure(widthSpec, View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)); switch (layoutParams.height){ case RecyclerView.LayoutParams.WRAP_CONTENT: measuredHeight += (getDecoratedMeasuredHeight(view) + margin); break; case RecyclerView.LayoutParams.MATCH_PARENT: default: measuredHeight += (layoutParams.height + margin); break; } } } if(measuredHeight > heightSize) super.onMeasure(recycler, state, widthSpec, heightSpec); else setMeasuredDimension(measuredWidth, measuredHeight); } }
实际使用:
recyclerView = (RecyclerView)findViewById(R.id.sv_rv); recyclerView.setLayoutManager(new RecyclerLayoutManager(getApplicationContext())); recyclerView.setAdapter(new RvAdapter());
实际效果:
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件
- SourceProvider.getJniDirectories