1. RecyclerView 高度动态调整
solution ( RecyclerView的高度控制都在 LayoutManager 中)
LinearLayoutManager exceptionLayoutManager = new LinearLayoutManager(this){
@Override public void onMeasure(RecyclerView.Recycler recycler,
RecyclerView.State state, int widthSpec, int heightSpec) { View view =
recycler.getViewForPosition(0); if (view != null) { measureChild(view,
widthSpec, heightSpec); //int measuredWidth =
View.MeasureSpec.getSize(widthSpec); int measuredHeight =
view.getMeasuredHeight(); int showHeight = measuredHeight *
state.getItemCount(); if(state.getItemCount() >= 5){ showHeight =
measuredHeight * 5; } setMeasuredDimension(widthSpec, showHeight); } } };
exceptionLayoutManager.setAutoMeasureEnabled(false);
exceptionListRecyclerview.setHasFixedSize(false);
exceptionListRecyclerview.setLayoutManager(exceptionLayoutManager);
exceptionListRecyclerview.setItemAnimator(new DefaultItemAnimator());
https://my.oschina.net/buobao/blog/651279
<https://my.oschina.net/buobao/blog/651279>
1.1 mLayoutManager.setAutoMeasureEnabled(false) mList.setHasFixedSize(false)
@Override public void onMeasure(RecyclerView.Recycler recycler,
RecyclerView.State state, int widthSpec,int heightSpec) { View view =
recycler.getViewForPosition(0); measureChild(view, widthSpec, heightSpec); int
measuredWidth = View.MeasureSpec.getSize(widthSpec); int measuredHeight =
view.getMeasuredHeight(); setMeasuredDimension(measuredWidth, measuredHeight);
} 1.2这里获取了view的高度,也就是item布局的高度,所以item的布局需要设定固定的高度,否则获取为0。其次,
这两个设置不能少,否则报错,这里和RecyclerView.onMeasure中的调用顺序有关,源码: protected void
onMeasure(int widthSpec, int heightSpec) { if (mLayout == null) {
defaultOnMeasure(widthSpec, heightSpec); return; } if (mLayout.mAutoMeasure) {
//这里为true会进入该分支 final int widthMode = MeasureSpec.getMode(widthSpec); final int
heightMode = MeasureSpec.getMode(heightSpec); final boolean skipMeasure =
widthMode == MeasureSpec.EXACTLY && heightMode == MeasureSpec.EXACTLY;
mLayout.onMeasure(mRecycler, mState, widthSpec, heightSpec);
//在调用mLayout的onMeasure方法时(被自定义复写的方法),mState.mItemCount为0,造成越界异常 if (skipMeasure
|| mAdapter == null) { return; } if (mState.mLayoutStep == State.STEP_START) {
dispatchLayoutStep1(); } // set dimensions in 2nd step. Pre-layout should
happen with old dimensions for // consistency
mLayout.setMeasureSpecs(widthSpec, heightSpec); mState.mIsMeasuring = true;
dispatchLayoutStep2(); // now we can get the width and height from the
children. mLayout.setMeasuredDimensionFromChildren(widthSpec, heightSpec); //
if RecyclerView has non-exact width and height and if there is at least one
child // which also has non-exact width & height, we have to re-measure. if
(mLayout.shouldMeasureTwice()) { mLayout.setMeasureSpecs(
MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.EXACTLY));
mState.mIsMeasuring = true; dispatchLayoutStep2(); // now we can get the width
and height from the children.
mLayout.setMeasuredDimensionFromChildren(widthSpec, heightSpec); } } else { if
(mHasFixedSize) { //这里不设置为false会造成与上面相同的问题 mLayout.onMeasure(mRecycler, mState,
widthSpec, heightSpec); return; } // custom onMeasure if
(mAdapterUpdateDuringMeasure) { eatRequestLayout();
processAdapterUpdatesAndSetAnimationFlags(); if
(mState.mRunPredictiveAnimations) { 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; } eatRequestLayout(); mLayout.onMeasure(mRecycler,
mState, widthSpec, heightSpec);
//在这里调用时mState.mItemCount才会有值,这与mLayout中获取当前item布局的方式有关:View view =
recycler.getViewForPosition(0); resumeRequestLayout(false); mState.mInPreLayout
= false; // clear } }
2. 关于RecyclerView的宽高调整
https://blog.csdn.net/crazyman2010/article/details/54315109
设置ItemView的间隔高宽 重写ItemDecoration的getItemOffsets函数即可:
recycleview.addItemDecoration(new RecyclerView.ItemDecoration() { @Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
RecyclerView.State state) { super.getItemOffsets(outRect, view, parent, state);
outRect.set(4, 4, 4, 4);//设置itemView中内容相对边框左,上,右,下距离 } });
3. ItemView适应RecyclerView
RecyclerView大小固定的情况下,根据RecyclerView的宽高设置ItemView的宽高,以达到recyclerview刚好显示N行/列数据的目的:
在原理是先计算出RecyclerView的宽高,然后在Adapter的onCreateViewHolder中设置view的高度:
比如一个垂直列表,希望recyclerview刚好显示三行,这样写: @Override public
ClubServiceAdapter.ServiceItemViewHolder onCreateViewHolder(ViewGroup parent,
int viewType) { View view =
LayoutInflater.from(parent.getContext()).inflate(布局文件, parent, false);
view.getLayoutParams().height = mRecyclerViewHeight/3; return new
ServiceItemViewHolder(view); }
热门工具 换一换