版权声明:本文为博主原创文章,未经博主允许不得转载。
我们先看一个效果,问题说的就是中间的Grid效果在Scrollview 嵌套recyclerview显示问题,在Android Api 24是好的,不过在5,1,1版本(api 22)缺出现了问题
最近项目中,有一个商品详情页面,页面有好几个网格页面,大家说,我们大可以用GridView去做,但是需要方的要求是,我们的网格的中间的线怎么做呢,对于GridView,我们知道我们可以这是一个背景,然后用verticalSpacing来做,这也算一个方法吧,但是对于Line线的计算是一个问题,有很多的计算逻辑,这样对代码的美观就造成了破坏,且看一段之前的代码:
- private void computeCompanyGridViewHeight(int size) {
- S.p("computeCompanyGridViewHeight size:" + size);
- if (size > 9) {
- size = 9;
- }
- int len = 3;
- if (size % 3 == 0) {
- len = size / 3 - 1;
- } else {
- len = size / 3;
- }
- int height = (len + 1) * Utils.dip2px(getActivity(), 58);
- ship_mid_companys.getLayoutParams().height = height;
- }
private void computeCompanyGridViewHeight(int size) {
S.p("computeCompanyGridViewHeight size:" + size);
if (size > 9) {
size = 9;
}
int len = 3;
if (size % 3 == 0) {
len = size / 3 - 1;
} else {
len = size / 3;
}
int height = (len + 1) * Utils.dip2px(getActivity(), 58);
ship_mid_companys.getLayoutParams().height = height;
}
我们这里采用RecycleView来实现。以前在ScrollView中嵌套嵌套ListView,无法正确的计算ListView的大小,现在我们在ScrollView中嵌套嵌套RecycleView的时候,也出现了计算不出高度的问题,于是有人想到我们是不是可以自己实现一个重写一个继承自RecycleView的类,重写OmMeasure,呵呵,但是实际上这是不行的,RecycleView是具体的一个控件,不相同与我们的ListView,这里参照之前网上的解决方案,我们可以继承自GridManager,然后对OnMeasure重写,其他的列表效果如此,
- public class WrappingGridLayoutManager extends GridLayoutManager {
- private int mwidth = 0;
- private int mheight = 0;
- public WrappingGridLayoutManager(Context context, int spanCount) {
- super(context, spanCount);
- }
- public WrappingGridLayoutManager(Context context, int spanCount, int orientation, boolean reverseLayout) {
- super(context, spanCount, orientation, reverseLayout);
- }
- private int[] mMeasuredDimension = new int[2];
- public int getMwidth() {
- return mwidth;
- }
- public void setMwidth(int mwidth) {
- this.mwidth = mwidth;
- }
- public int getMheight() {
- return mheight;
- }
- public void setMheight(int mheight) {
- this.mheight = mheight;
- }
- @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;
- int count = getItemCount();
- int span = getSpanCount();
- <span style="color:#ff0000;"> for (int i = 0; i < count; i++) {
- measureScrapChild(recycler, i,
- View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),
- View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),
- mMeasuredDimension);</span>
- if (getOrientation() == HORIZONTAL) {
- if (i % span == 0) {
- width = width + mMeasuredDimension[0];
- }
- if (i == 0) {
- height = mMeasuredDimension[1];
- }
- } else {
- if (i % span == 0) {
- 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:
- }
- setMheight(height);
- setMwidth(width);
- setMeasuredDimension(width, height);
- }
- private void measureScrapChild(RecyclerView.Recycler recycler, int position, int widthSpec,
- int heightSpec, int[] measuredDimension) {
- if (position < getItemCount()) {
- try {
- View view = recycler.getViewForPosition(0);//fix 动态添加时报IndexOutOfBoundsException
- 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);
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
- }
public class WrappingGridLayoutManager extends GridLayoutManager {
private int mwidth = 0;
private int mheight = 0;
public WrappingGridLayoutManager(Context context, int spanCount) {
super(context, spanCount);
}
public WrappingGridLayoutManager(Context context, int spanCount, int orientation, boolean reverseLayout) {
super(context, spanCount, orientation, reverseLayout);
}
private int[] mMeasuredDimension = new int[2];
public int getMwidth() {
return mwidth;
}
public void setMwidth(int mwidth) {
this.mwidth = mwidth;
}
public int getMheight() {
return mheight;
}
public void setMheight(int mheight) {
this.mheight = mheight;
}
@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;
int count = getItemCount();
int span = getSpanCount();
for (int i = 0; i < count; i++) {
measureScrapChild(recycler, i,
View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),
View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),
mMeasuredDimension);
if (getOrientation() == HORIZONTAL) {
if (i % span == 0) {
width = width + mMeasuredDimension[0];
}
if (i == 0) {
height = mMeasuredDimension[1];
}
} else {
if (i % span == 0) {
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:
}
setMheight(height);
setMwidth(width);
setMeasuredDimension(width, height);
}
private void measureScrapChild(RecyclerView.Recycler recycler, int position, int widthSpec,
int heightSpec, int[] measuredDimension) {
if (position < getItemCount()) {
try {
View view = recycler.getViewForPosition(0);//fix 动态添加时报IndexOutOfBoundsException
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);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
- private void measureScrapChild(RecyclerView.Recycler recycler, int position, int widthSpec,
- int heightSpec, int[] measuredDimension) {
- if (position < getItemCount()) {
- try {
- View view = recycler.getViewForPosition(0);//fix 动态添加时报IndexOutOfBoundsException
- 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);
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
private void measureScrapChild(RecyclerView.Recycler recycler, int position, int widthSpec,
int heightSpec, int[] measuredDimension) {
if (position < getItemCount()) {
try {
View view = recycler.getViewForPosition(0);//fix 动态添加时报IndexOutOfBoundsException
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);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
至于划线,我们需要另一个类实现,这用到了Recycle的一个方法
recyclerView.addItemDecoration(new SupportGridItemLine(this));
Line线计算类:
- public class SupportGridItemLine extends RecyclerView.ItemDecoration {
- private static final int[] ATTRS = new int[]{android.R.attr.listDivider};
- private Drawable mDivider;
- public SupportGridItemLine(Context context) {
- final TypedArray a = context.obtainStyledAttributes(ATTRS);
- mDivider = a.getDrawable(0);
- a.recycle();
- }
- @Override
- public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
- drawHorizontal(c, parent);
- drawVertical(c, parent);
- }
- private int getSpanCount(RecyclerView parent) {
- // 列数
- int spanCount = -1;
- RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
- if (layoutManager instanceof GridLayoutManager) {
- spanCount = ((GridLayoutManager) layoutManager).getSpanCount();
- } else if (layoutManager instanceof StaggeredGridLayoutManager) {
- spanCount = ((StaggeredGridLayoutManager) layoutManager)
- .getSpanCount();
- }
- return spanCount;
- }
- public void drawHorizontal(Canvas c, RecyclerView parent) {
- int childCount = parent.getChildCount();
- for (int i = 0; i < childCount; i++) {
- final View child = parent.getChildAt(i);
- final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
- .getLayoutParams();
- final int left = child.getLeft() - params.leftMargin;
- final int right = child.getRight() + params.rightMargin
- + mDivider.getIntrinsicWidth();
- final int top = child.getBottom() + params.bottomMargin;
- final int bottom = top + mDivider.getIntrinsicHeight();
- mDivider.setBounds(left, top, right, bottom);
- mDivider.draw(c);
- }
- }
- public void drawVertical(Canvas c, RecyclerView parent) {
- final int childCount = parent.getChildCount();
- for (int i = 0; i < childCount; i++) {
- final View child = parent.getChildAt(i);
- final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
- .getLayoutParams();
- final int top = child.getTop() - params.topMargin;
- final int bottom = child.getBottom() + params.bottomMargin;
- final int left = child.getRight() + params.rightMargin;
- final int right = left + mDivider.getIntrinsicWidth();
- mDivider.setBounds(left, top, right, bottom);
- mDivider.draw(c);
- }
- }
- private boolean isLastColum(RecyclerView parent, int pos, int spanCount,
- int childCount) {
- RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
- if (layoutManager instanceof GridLayoutManager) {
- if ((pos + 1) % spanCount == 0)// 如果是最后一列,则不需要绘制右边
- {
- return true;
- }
- } else if (layoutManager instanceof StaggeredGridLayoutManager) {
- int orientation = ((StaggeredGridLayoutManager) layoutManager)
- .getOrientation();
- if (orientation == StaggeredGridLayoutManager.VERTICAL) {
- if ((pos + 1) % spanCount == 0)// 如果是最后一列,则不需要绘制右边
- {
- return true;
- }
- } else {
- childCount = childCount - childCount % spanCount;
- if (pos >= childCount)// 如果是最后一列,则不需要绘制右边
- return true;
- }
- }
- return false;
- }
- private boolean isLastRaw(RecyclerView parent, int pos, int spanCount,
- int childCount) {
- RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
- if (layoutManager instanceof GridLayoutManager) {
- childCount = childCount - childCount % spanCount;
- if (pos >= childCount)// 如果是最后一行,则不需要绘制底部
- return true;
- } else if (layoutManager instanceof StaggeredGridLayoutManager) {
- int orientation = ((StaggeredGridLayoutManager) layoutManager)
- .getOrientation();
- // StaggeredGridLayoutManager 且纵向滚动
- if (orientation == StaggeredGridLayoutManager.VERTICAL) {
- childCount = childCount - childCount % spanCount;
- // 如果是最后一行,则不需要绘制底部
- if (pos >= childCount)
- return true;
- } else
- // StaggeredGridLayoutManager 且横向滚动
- {
- // 如果是最后一行,则不需要绘制底部
- if ((pos + 1) % spanCount == 0) {
- return true;
- }
- }
- }
- return false;
- }
- @Override
- public void getItemOffsets(Rect outRect, int itemPosition,
- RecyclerView parent) {
- int spanCount = getSpanCount(parent);
- int childCount = parent.getAdapter().getItemCount();
- if (isLastRaw(parent, itemPosition, spanCount, childCount))// 如果是最后一行,则不需要绘制底部
- {
- outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
- } else if (isLastColum(parent, itemPosition, spanCount, childCount))// 如果是最后一列,则不需要绘制右边
- {
- outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
- } else {
- outRect.set(0, 0, mDivider.getIntrinsicWidth(),
- mDivider.getIntrinsicHeight());
- }
- }
- }
public class SupportGridItemLine extends RecyclerView.ItemDecoration {
private static final int[] ATTRS = new int[]{android.R.attr.listDivider};
private Drawable mDivider;
public SupportGridItemLine(Context context) {
final TypedArray a = context.obtainStyledAttributes(ATTRS);
mDivider = a.getDrawable(0);
a.recycle();
}
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
drawHorizontal(c, parent);
drawVertical(c, parent);
}
private int getSpanCount(RecyclerView parent) {
// 列数
int spanCount = -1;
RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
if (layoutManager instanceof GridLayoutManager) {
spanCount = ((GridLayoutManager) layoutManager).getSpanCount();
} else if (layoutManager instanceof StaggeredGridLayoutManager) {
spanCount = ((StaggeredGridLayoutManager) layoutManager)
.getSpanCount();
}
return spanCount;
}
public void drawHorizontal(Canvas c, RecyclerView parent) {
int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = parent.getChildAt(i);
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
.getLayoutParams();
final int left = child.getLeft() - params.leftMargin;
final int right = child.getRight() + params.rightMargin
+ mDivider.getIntrinsicWidth();
final int top = child.getBottom() + params.bottomMargin;
final int bottom = top + mDivider.getIntrinsicHeight();
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}
public void drawVertical(Canvas c, RecyclerView parent) {
final int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = parent.getChildAt(i);
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
.getLayoutParams();
final int top = child.getTop() - params.topMargin;
final int bottom = child.getBottom() + params.bottomMargin;
final int left = child.getRight() + params.rightMargin;
final int right = left + mDivider.getIntrinsicWidth();
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}
private boolean isLastColum(RecyclerView parent, int pos, int spanCount,
int childCount) {
RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
if (layoutManager instanceof GridLayoutManager) {
if ((pos + 1) % spanCount == 0)// 如果是最后一列,则不需要绘制右边
{
return true;
}
} else if (layoutManager instanceof StaggeredGridLayoutManager) {
int orientation = ((StaggeredGridLayoutManager) layoutManager)
.getOrientation();
if (orientation == StaggeredGridLayoutManager.VERTICAL) {
if ((pos + 1) % spanCount == 0)// 如果是最后一列,则不需要绘制右边
{
return true;
}
} else {
childCount = childCount - childCount % spanCount;
if (pos >= childCount)// 如果是最后一列,则不需要绘制右边
return true;
}
}
return false;
}
private boolean isLastRaw(RecyclerView parent, int pos, int spanCount,
int childCount) {
RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
if (layoutManager instanceof GridLayoutManager) {
childCount = childCount - childCount % spanCount;
if (pos >= childCount)// 如果是最后一行,则不需要绘制底部
return true;
} else if (layoutManager instanceof StaggeredGridLayoutManager) {
int orientation = ((StaggeredGridLayoutManager) layoutManager)
.getOrientation();
// StaggeredGridLayoutManager 且纵向滚动
if (orientation == StaggeredGridLayoutManager.VERTICAL) {
childCount = childCount - childCount % spanCount;
// 如果是最后一行,则不需要绘制底部
if (pos >= childCount)
return true;
} else
// StaggeredGridLayoutManager 且横向滚动
{
// 如果是最后一行,则不需要绘制底部
if ((pos + 1) % spanCount == 0) {
return true;
}
}
}
return false;
}
@Override
public void getItemOffsets(Rect outRect, int itemPosition,
RecyclerView parent) {
int spanCount = getSpanCount(parent);
int childCount = parent.getAdapter().getItemCount();
if (isLastRaw(parent, itemPosition, spanCount, childCount))// 如果是最后一行,则不需要绘制底部
{
outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
} else if (isLastColum(parent, itemPosition, spanCount, childCount))// 如果是最后一列,则不需要绘制右边
{
outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
} else {
outRect.set(0, 0, mDivider.getIntrinsicWidth(),
mDivider.getIntrinsicHeight());
}
}
}
- WrappingGridLayoutManager manager = new WrappingGridLayoutManager(getActivity(), 2);//2表示2个单元格
- manager.setOrientation(GridLayoutManager.VERTICAL);
- manager.setSmoothScrollbarEnabled(true);
- recyclerView.setLayoutManager(manager);
- recyclerView.setHasFixedSize(true);
- recyclerView.setNestedScrollingEnabled(false);
- recyclerView.addItemDecoration(new SupportGridItemLine(getActivity()));
WrappingGridLayoutManager manager = new WrappingGridLayoutManager(getActivity(), 2);//2表示2个单元格
manager.setOrientation(GridLayoutManager.VERTICAL);
manager.setSmoothScrollbarEnabled(true);
recyclerView.setLayoutManager(manager);
recyclerView.setHasFixedSize(true);
recyclerView.setNestedScrollingEnabled(false);
recyclerView.addItemDecoration(new SupportGridItemLine(getActivity()));
至于网上有人说的,在RecycleView外加一个布局,不知道什么原因,我这里还是没有解决。
- <RelativeLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:descendantFocusability="blocksDescendants">
- <android.support.v7.widget.RecyclerView
- android:id="@+id/menuRv"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginLeft="@dimen/margin_16"
- android:layout_marginRight="@dimen/margin_16">
- </android.support.v7.widget.RecyclerView>
- </RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:descendantFocusability="blocksDescendants">
<android.support.v7.widget.RecyclerView
android:id="@+id/menuRv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/margin_16"
android:layout_marginRight="@dimen/margin_16">
</android.support.v7.widget.RecyclerView>
</RelativeLayout>
好了,姑且记下,帮助后来人,有疑问请加群:278792776