自定义LayoutManager的流程?

最近加入一个Android每日一问的知识小组,对技术查漏补缺。
Android 每日一问

正好看到自定义LayoutManager流程?这个问题,虽然这前知道LayoutManager自定义可以做出各种各样的效果,但是从来没有去撸代码实践过。借这个机会,去了解学习一下。

参考文档:
打造属于你的LayoutManager
由旋转画廊,看自定义RecyclerView.LayoutManager

由于第一个参考文档已经写明了详情的过程,我也只是根据其自己撸了一遍而已,代码就不再处理,只把流程写一下,作为这个知识点记录。

1. 复写获得默认的LayoutParams对象。

generateDefaultLayoutParams()。新建继承类就必须复写的

2. 复写子View 的摆放。

onLayoutChildren()。需要在里面计算每一个子View摆放的位置。

  • 通过addView()将View添加到RecyclerView里面。
  • measureChildWithMargins(),测量view的布局。
  • layoutDecorated(),将view 真正摆放到相应的位置。

3. 允许RecyclerView水平或竖直滑动

  • canScrollVertically() 或 canScrollHorizontally(),这两个默认是false,不允许滑动。
  • scrollVerticallyBy(),处理整体滑动时view的回收显示。

4. 添加缓存,从而快速复用

detachAndScrapAttachedViews()移除所有,重新添加(复用),通过addView,measureChildWithMargins,layoutDecorated添加到RecyclerView 里面。 这里使用的最简单的方法,其实还可以在里面做一个当前可见的集合,然后根据上滑下滑添加某一个,性能会高,但是本质一样,都是复用。

遇到的一个小坑,由于RecyclerView设置高度的wrap_content,导致无法显示出子View,在设置为match_parent之可见。
原因: wrap_content 在LayoutManager.onMeasure()时,其mode 为 AT_MOST。而AT_MOST在RecyclerView.onMeasure()时,使用defalutOnMeasure(),该函数在获取 高度其实取的最小值,若没有设置miniHeight,及padingtop padingbutton,那么就必定为0,这也就是wrap_content显示不出来的原因。

    void defaultOnMeasure(int widthSpec, int heightSpec) {
        // calling LayoutManager here is not pretty but that API is already public and it is better
        // than creating another method since this is internal.
        final int width = LayoutManager.chooseSize(widthSpec,
                getPaddingLeft() + getPaddingRight(),
                ViewCompat.getMinimumWidth(this));
        final int height = LayoutManager.chooseSize(heightSpec,
                getPaddingTop() + getPaddingBottom(),
                ViewCompat.getMinimumHeight(this));

        setMeasuredDimension(width, height);
    }


public static int chooseSize(int spec, int desired, int min) {
            final int mode = View.MeasureSpec.getMode(spec);
            final int size = View.MeasureSpec.getSize(spec);
            switch (mode) {
                case View.MeasureSpec.EXACTLY:
                    return size;
                case View.MeasureSpec.AT_MOST:
                    return Math.min(size, Math.max(desired, min));
                case View.MeasureSpec.UNSPECIFIED:
                default:
                    return Math.max(desired, min);
            }
        }

解决方法:可以在LayoutManager的onMeasure里面,将其Mode及高度都强制修改即可。我的修改方案:

    //LayoutManager.onMeasure()
    @Override
    public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state, int widthSpec, int heightSpec) {
        final int heightMode = View.MeasureSpec.getMode(heightSpec);
        int height = View.MeasureSpec.getSize(heightSpec);

        if (heightMode == View.MeasureSpec.AT_MOST) {
            if(totalHeight == 0){
                for (int i = 0; i < getItemCount(); i++) {
                    View viewItem = recycler.getViewForPosition(i);
                    measureChildWithMargins(viewItem, 0, 0);

                    int w = getDecoratedMeasuredWidth(viewItem);
                    int h = getDecoratedMeasuredHeight(viewItem);
                    totalHeight +=h;
                }
            }
            if(totalHeight< height){
                height = totalHeight;
            }
            height = (height & ~(0x3 << 30)) | (View.MeasureSpec.EXACTLY & (0x3 << 30));
        }
        super.onMeasure(recycler, state, widthSpec, height);

    }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,392评论 5 470
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,258评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,417评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,992评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,930评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,199评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,652评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,327评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,463评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,382评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,432评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,118评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,704评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,787评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,999评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,476评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,057评论 2 341