RecyclerView自适应高度之GridLayoutMana
2018-07-27 本文已影响327人
wcdd
在布局中RecyclerView添加android:layout_height="wrap_content"这一属性,发现竟然不起作用,RecyclerView的item加载完成,屏幕下方所有的区域都会被占用,若为一般界面倒是看不出太大的影响,但当Activity为弹窗显示时影响就很大了,如下图效果:
图一.png
我们想要实现的效果如下:
图二.png
我们通过自定义MyGridLayoutManager继承GridLayoutManager来解决这个问题,直接上代码:
import android.content.Context;
import android.graphics.Rect;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.view.ViewGroup;
public class MyGridLayoutManager extends GridLayoutManager {
public MyGridLayoutManager(Context context, int spanCount) {
super(context, spanCount);
}
private int[] measuredSize = 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 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), measuredSize);
if (i % spanCount == 0) {
spanWidth = measuredSize[0];
spanHeight = measuredSize[1];
} else {
if (getOrientation() == VERTICAL) {
spanWidth += measuredSize[0];
spanHeight = Math.max(spanHeight, measuredSize[1]);
} else {
spanWidth = Math.max(spanWidth, measuredSize[0]);
spanHeight += measuredSize[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 finalWidth;
int finalHeight;
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);
}
}
}
在代码中使用方法
mrecycler.setLayoutManager(new MyGridLayoutManager(this,3));