我们先看一个效果,问题说的就是中间的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;
	}

我们这里采用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();
            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();
                }
            }
    }

至于划线,我们需要另一个类实现,这用到了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());
        }
    }
}

好了,最后我们在使用的时候,先对RecycleView初始化相关的属性参数:

 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>

好了,姑且记下,帮助后来人,有疑问请加群:278792776

解决Scrollview 嵌套recyclerview不能显示,高度不正常的问题的更多相关文章

  1. 解决ScrollView嵌套RecyclerView的显示及滑动问题

        项目中时常需要实现在ScrollView中嵌入一个或多个RecyclerView.这一做法通常会导致如下几个问题 页面滑动卡顿 ScrollView高度显示不正常 RecyclerView内容 ...

  2. 一键解决ScrollView嵌套ListView仅仅显示一行的问题

    /** * 解决ScrollView嵌套ListView仅仅显示一行的问题 * * @param listView */ private void setListViewHeightBasedOnCh ...

  3. 解决ScrollView嵌套RecyclerView出现item显示不全的问题

      问题:ScrollView嵌套RecyclerView时,RecyclerView的item显示不全 出现问题不要慌,耐心解决才是王道,哈哈.首先说下出现这个问题的情景吧,首先声明这个问题在23版 ...

  4. Android在开发中的使用技巧之解决ScrollView嵌套RecyclerView出现的系列问题

    根据已上线的app里总结出来的实用小技巧 相信大家都遇到过ScrollView嵌套RecyclerView或者RecyclerView嵌套RecyclerView来使用, 也会遇到一堆奇奇怪怪的问题, ...

  5. Android 解决ScrollView嵌套RecyclerView导致滑动不流畅的问题

    最近做的项目中遇到了ScrollView嵌套RecyclerView,刚写完功能测试,直接卡出翔了,后来通过网上查找资料和 自己的实践,找出了两种方法解决这个问题. 首先来个最简单的方法: recyc ...

  6. 解决ScrollView 嵌套 GridView 单行显示问题

    简单重写GridView package com.hh.beauter.my_ui; import android.content.Context; import android.util.Attri ...

  7. ScrollView嵌套ListView只显示一行之计算的高度不正确的解决办法(转)

    ScrollView嵌套ListView只显示一行之计算的高度不正确的解决办法 分类: android应用开发2013-12-19 09:40 1045人阅读 评论(3) 收藏 举报 AndroidS ...

  8. Scrollview 嵌套 RecyclerView 及在Android 5.1版本滑动时 惯性消失问题

    标签:scrollview   android   滑动   嵌套 scrollview 嵌套recyclerview 时,recyclerview不显示,这就需要我们自己计算recyclerview ...

  9. (转载) Scrollview 嵌套 RecyclerView 及在Android 5.1版本滑动时 惯性消失问题

    Scrollview 嵌套 RecyclerView 及在Android 5.1版本滑动时 惯性消失问题 标签: scrollviewandroid滑动嵌套 2015-07-16 17:24 1112 ...

随机推荐

  1. linux内核中的链表

    1.内核中的链表 linux内核链表与众不同,他不是把将数据结构塞入链表,而是将链表节点塞入数据,在2.1内核中引入了官方链表,从此内核中所有的链表使用都采用此链表,千万不要在重复造车轮子了!链表实现 ...

  2. SpringCloud学习之sleuth&zipkin

    一.调用链跟踪的必要性 首先我们简单来看一下下单到支付的过程,别的不多说,在业务复杂的时候往往服务会一层接一层的调用,当某一服务环节出现响应缓慢时会影响整个服务的响应速度,由于业务调用层次很“深”,那 ...

  3. RTX 无法刷新组织架构的处理方法总结

    文章一: 刷新组织架构问题1."客户端不能获取正确的组织架构"或"新增加的人员刷新不了组织架构"首先要判断是RTX服务器引起的异常还是一些客户端出现的异常,判断 ...

  4. 我在 Ubuntu 下使用 Sublime 编写 python 代码时遇到并解决的问题

    Ubuntu 下 Sublime 无法输入中文 解决方法如下: sudo apt-get update && sudo apt-get upgrade 克隆项目到本地 : git cl ...

  5. Linux系统中安装Oracle过程记录

    第一章 安装数据库软件 1.1 修改密码及创建目录和权限 创建oracle用户和组 创建相关目录并赋权 1.2 设置oracle用户环境变量 ORACLE_BASE:产品基目录 ORACLE_HOME ...

  6. Docker容器访问控制

    容器的访问控制,主要通过 Linux 上的 iptables 防火墙来进行管理和实现.iptables 是 Linux 上默认的防火墙软件,在大部分发行版中都自带. 容器访问外部网络 容器要想访问外部 ...

  7. Java中常用缓存Cache机制的实现

    缓存,就是将程序或系统经常要调用的对象存在内存中,一遍其使用时可以快速调用,不必再去创建新的重复的实例. 这样做可以减少系统开销,提高系统效率. 缓存主要可分为二大类: 一.通过文件缓存,顾名思义文件 ...

  8. intel-hadoop/HiBench流程分析----以贝叶斯算法为例

    1.HiBench算法简介 Hibench 包含9个典型的hadoop负载(micro benchmarks,hdfs benchmarks,web search bench marks,machin ...

  9. Android音频处理——通过AudioRecord去保存PCM文件进行录制,播放,停止,删除功能

    Android音频处理--通过AudioRecord去保存PCM文件进行录制,播放,停止,删除功能 音频这方面很博大精深,我这里肯定讲不了什么高级的东西,最多也只是一些基础类知识,首先,我们要介绍一下 ...

  10. Ubuntu等Linux系统显卡性能测试软件 Unigine 3D

    Ubuntu等Linux系统显卡性能测试软件 Unigine 3D Ubuntu Intel显卡驱动安装,请参考: http://blog.csdn.net/zhangrelay/article/de ...