前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >解决Scrollview 嵌套recyclerview不能显示,高度不正常的问题

解决Scrollview 嵌套recyclerview不能显示,高度不正常的问题

作者头像
xiangzhihong
发布于 2018-02-05 07:11:57
发布于 2018-02-05 07:11:57
3.6K00
代码可运行
举报
文章被收录于专栏:向治洪向治洪
运行总次数:0
代码可运行

我们先看一个效果,问题说的就是中间的Grid效果在Scrollview 嵌套recyclerview显示问题,在Android Api 24是好的,不过在5,1,1版本(api 22)缺出现了问题

最近项目中,有一个商品详情页面,页面有好几个网格页面,大家说,我们大可以用GridView去做,但是需要方的要求是,我们的网格的中间的线怎么做呢,对于GridView,我们知道我们可以这是一个背景,然后用verticalSpacing来做,这也算一个方法吧,但是对于Line线的计算是一个问题,有很多的计算逻辑,这样对代码的美观就造成了破坏,且看一段之前的代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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重写,其他的列表效果如此,

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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();
                }
            }
    }
}
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 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的一个方法

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
recyclerView.addItemDecoration(new SupportGridItemLine(this));

Line线计算类:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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初始化相关的属性参数:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 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外加一个布局,不知道什么原因,我这里还是没有解决。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 <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>
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2016-10-29 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
解读 RAG 中的 embedding model
在当前人工智能潮流中,RAG 技术备受关注,诸如 RAGFlow、Qanything、Dify、FastGPT 等 RAG 引擎逐渐受到广泛关注。在这些引擎的背后,嵌入模型扮演着关键角色,对于整个系统起着至关重要的作用。让我们一同探究这个神秘的嵌入模型!
福大大架构师每日一题
2025/03/13
1600
解读 RAG 中的 embedding model
Word2vec原理及其Python实现「建议收藏」
在NLP(自然语言处理)里面,最细粒度的是词语,词语组成句子,句子再组成段落、篇章、文档。所以要处理 NLP 的问题,首先就要拿词语开刀。
全栈程序员站长
2022/08/30
3.8K0
Word2vec原理及其Python实现「建议收藏」
词嵌入与NLP
定义:指把一个维数为所有词的数量的高维空间嵌入到一个维数低得多的连续向量空间中,每个单词或词组被映射为实数域上的向量。
Lansonli
2021/10/09
5230
一文详尽之Embedding(向量表示)!
文本是一类非常重要的非结构化数据,如何表示文本数据一直是机器学习领域的一个重点研究方向。文本向量就是深度学习时代产生的一种文本表示的方法。
Datawhale
2025/01/19
3.5K0
一文详尽之Embedding(向量表示)!
算法金 | 没有思考过 Embedding,不足以谈 AI
在当今的人工智能(AI)领域,Embedding 是一个不可或缺的概念。如果你没有深入理解过 Embedding,那么就无法真正掌握 AI 的精髓。接下来,我们将深入探讨 Embedding 的基本概念。
算法金
2024/06/27
6800
算法金 | 没有思考过 Embedding,不足以谈 AI
词向量技术 | 从word2vec到ELMo
"词和句子的嵌入已成为所有基于深度学习的自然语言处理(NLP)系统的重要组成部分,它们在固定长度的稠密向量中编码单词和句子,以大幅度提高神经网络处理文本数据的能力。"
用户1332428
2018/08/17
2.5K0
词向量技术 | 从word2vec到ELMo
Word2vec理论基础——词向量
我们希望原始文本信息能够得到保留,例如国王和女王之间的关系和男人与女人之间的关系应是特别接近的,法国和巴黎之间关系与德国和巴黎的关系也是接近的。
Hsinyan
2022/06/19
5410
Word2vec理论基础——词向量
文本的词嵌入是什么?
词嵌入(Word embeddings)是一种单词的表示形式,它允许意义相似的单词具有类似的表示形式。
StoneDemo
2018/02/11
4.4K0
文本的词嵌入是什么?
NLP︱高级词向量表达(二)——FastText(简述、学习笔记)「建议收藏」
1、NLP︱高级词向量表达(一)——GloVe(理论、相关测评结果、R&python实现、相关应用) 2、NLP︱高级词向量表达(二)——FastText(简述、学习笔记) 3、NLP︱高级词向量表达(三)——WordRank(简述) 4、其他NLP词表示方法paper:从符号到分布式表示NLP中词各种表示方法综述
全栈程序员站长
2022/08/10
1.2K0
NLP︱高级词向量表达(二)——FastText(简述、学习笔记)「建议收藏」
[DeeplearningAI笔记]序列模型2.1-2.2词嵌入word embedding
吴恩达老师课程原地址: https://mooc.study.163.com/smartSpec/detail/1001319001.htm
演化计算与人工智能
2020/08/14
5720
[DeeplearningAI笔记]序列模型2.1-2.2词嵌入word embedding
自然语言处理基础:上下文词表征入门解读
摘要:这篇介绍论文的目的是讲述如何让计算机处理语言的故事。这是自然语言处理(NLP)领域的一部分,而 NLP 又是人工智能的一个分支领域。本文的目标是让广泛的受众都能获得对计算机编程的基本理解,但其中避免了详细的数学描述,并且不会给出任何算法。本文的重点也并非 NLP 的任何特定的应用,比如翻译、问答或信息抽取。这里给出的思想经过了许多研究者数十年的发展,所以引用的文献并非详尽无遗,但能为读者指出一些在作者看来影响深远的论文。在读完本文之后,你应当会有对词向量(也被称为词嵌入)的大致理解:它们为何存在、它们解决的是什么问题、它们来自何处、它们如何随时间变化、有关它们还有那些有待解决的问题。建议已经熟悉词向量的读者跳至第 5 节查看有关当前最新进展「上下文词向量」的讨论。
机器之心
2019/03/12
8420
自然语言处理基础:上下文词表征入门解读
词嵌入方法(Word Embedding)
Word Embedding是NLP中的一种技术,通过将单词映射到一个空间向量来表示每个单词
@小森
2024/11/07
8391
词嵌入方法(Word Embedding)
LLM的构建基石:向量、Token和嵌入
当你处理 LLMs 时,你经常会遇到术语“向量”,“Token”和“嵌入”。在深入构建聊天机器人和 AI 助手之前,充分理解这些概念非常重要。随着多模态方法的兴起,这些术语不仅仅局限于大型语言模型(LLMs),还可以解释图像和视频。
云云众生s
2024/03/28
7730
LLM的构建基石:向量、Token和嵌入
大语言模型-01-语言模型发展历程-02-从神经网络到ELMo
早期工作MLP(Multilayer Perceptron,MLP,多层感知机): NNLM(Neural Network Language Model,神经网络语言模型),单词映射到词向量,再由神经网络预测当前时刻词汇。是一种通过神经网络进行语言建模的技术,通常用于预测序列中的下一个词。
IT从业者张某某
2025/03/15
1830
大语言模型-01-语言模型发展历程-02-从神经网络到ELMo
万字长文——这次彻底了解LLM大语言模型
自然语言处理领域正在经历着一场又一场的革命,各类技术层出不穷,不断的改变我们对文本的理解方式和文本生成方式。类似与蝴蝶效应,这场革命不仅提高了机器翻译、文本摘要、文本分类等任务的性能,还在各行各业引发了巨大的变革。越来越 多的行业AI化、智能化。在本小节,将介绍一些语言模型中的核心概念,为更好的理解大语言模型做铺垫。
聪明鱼
2023/12/07
6.4K2
【算法】word2vec与doc2vec模型
小编邀请您,先思考: 1 word2vec算法原理是什么? 2 word2vec与doc2vec有什么差异? 3 如何做word2vec和doc2vec? 深度学习掀开了机器学习的新篇章,目前深度学习应用于图像和语音已经产生了突破性的研究进展。深度学习一直被人们推崇为一种类似于人脑结构的人工智能算法,那为什么深度学习在语义分析领域仍然没有实质性的进展呢?   引用三年前一位网友的话来讲:   “Steve Renals算了一下icassp录取文章题目中包含deep learning的数量,发现有44篇,而n
陆勤_数据人网
2018/03/20
2.3K0
【算法】word2vec与doc2vec模型
10分钟了解图嵌入
去年,图嵌入在企业知识图谱(EKG)策略中变得越来越重要。图形嵌入将很快成为在大型十亿顶点EKG中快速找到相似项目的实际方法。实时相似性计算对于许多领域至关重要,例如推荐,最佳行动和队列构建。
deephub
2020/12/11
5050
10分钟了解图嵌入
NLP︱高级词向量表达(二)——FastText(简述、学习笔记)
本文介绍了fastText这款基于子词(subword)的文本分类模型,该模型在文本分类任务上表现优异,具有较快的训练速度,并且支持多种语言。fastText采用子词建模,将文本拆分成子词,然后利用这些子词来训练模型。相较于word2vec和BERT等模型,fastText具有更高的训练效率和更好的性能。同时,fastText还可以用于多语言文本分类,并且不需要额外的预处理或数据标注。
悟乙己
2018/01/02
4K1
NLP︱高级词向量表达(二)——FastText(简述、学习笔记)
词向量发展历程:技术及实战案例
词向量(Word Vector)或词嵌入(Word Embedding)是自然语言处理(NLP)中的一项基础技术,它允许我们将自然语言中的词汇表示为实数向量。这些向量通常存在于一个高维空间内,其中每一个维度都可能代表着某种语义属性。通过这种转换,机器学习模型可以捕捉到词语之间复杂的关系,如语义相似性、反义、上下位关系等。
TechLead
2024/04/17
1.9K0
词向量发展历程:技术及实战案例
乱炖“简书交友”数据之代码(2)
继续更新出来本系列的代码:乱炖数据之2700余篇“简书交友”专题文章数据的花式玩法
古柳_DesertsX
2018/08/21
7820
乱炖“简书交友”数据之代码(2)
相关推荐
解读 RAG 中的 embedding model
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档