RecyclerView相信大家都不会陌生,作为ListView的替代控件,为大家提供了很多方便,在使用的时候我们会发现一个setLayoutManager这样一个方法,他的参数可以是LinearLayoutManager,GridLayoutManager以及特别酷炫的StaggeredGridLayoutManager,至于区别呢,大家自己动手,今天主要记录一下GridLayoutManager这个类。
GridLayoutManager主要是实现GridView这样的效果的,用着用着你会发现一个坑,那就是这个家伙高度无法设置为Wrap_content,就是说无论有几个子View高度都是一样的(Vertical情况下),都是MATCH_PARENT,效果如下:
解决的方式是写个子类继承GridLayoutManager,如下:
使用上述的类之后呢,效果就是class WrappableGridLayoutManager extends GridLayoutManager { public WrappableGridLayoutManager(Context context, int spanCount) { super(context, spanCount); } private int[] mMeasuredDimension = new int[2]; @Override public boolean canScrollVertically() { return false; } @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 spanWidth = 0; int spanHeight = 0; int viewWidth = 0; int viewHeight = 0; int spanCount = getSpanCount(); 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(i%spanCount==0){ spanWidth=mMeasuredDimension[0]; spanHeight=mMeasuredDimension[1]; }else{ if(getOrientation()==VERTICAL){ spanWidth+=mMeasuredDimension[0]; spanHeight=Math.max(spanHeight,mMeasuredDimension[1]); }else{ spanWidth=Math.max(spanWidth,mMeasuredDimension[0]); spanHeight+=mMeasuredDimension[1]; } } if(i%spanCount==spanCount-1||i==getItemCount()-1){ if(getOrientation()==VERTICAL){ viewWidth=Math.max(viewWidth,spanWidth); viewHeight+=spanHeight; }else{ viewWidth+=spanWidth; viewHeight=Math.max(viewHeight,spanHeight); } } } int finalHeight; int finalWidth; switch (widthMode){ case View.MeasureSpec.EXACTLY: finalWidth=widthSize; break; case View.MeasureSpec.AT_MOST: finalWidth=Math.min(widthSize,viewWidth); break; case View.MeasureSpec.UNSPECIFIED: finalWidth=viewWidth; break; default: finalWidth=widthSize; break; } switch (heightMode){ case View.MeasureSpec.EXACTLY: finalHeight=heightSize; break; case View.MeasureSpec.AT_MOST: finalHeight=Math.min(heightSize,viewHeight); break; case View.MeasureSpec.UNSPECIFIED: finalHeight=viewHeight; break; default: finalHeight=heightSize; break; } setMeasuredDimension(finalWidth,finalHeight); } 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; Rect decoratorRect=new Rect(); calculateItemDecorationsForChild(view,decoratorRect); measuredDimension[0]+=decoratorRect.left; measuredDimension[0]+=decoratorRect.right; measuredDimension[1]+=decoratorRect.top; measuredDimension[1]+=decoratorRect.bottom; recycler.recycleView(view); } } }
当然,我使用了addItemDecotation方法,这个就不多说了。打个广告http://stay4it.com/,大神带你飞,不喜勿喷。