sunflower-zyb / Blog

日常阅读的好文章、遇到的小问题、使用的小工具
47 stars 8 forks source link

# RecyclerView使用GridLayoutManager,高度设置为wrap_content时无效 #3

Open sunflower-zyb opened 9 years ago

sunflower-zyb commented 9 years ago

RecyclerView使用GridLayoutManager,高度设置为wrap_content时无效

标签(空格分隔): RecyclerView GridLayoutManager wrap_content


今天在使用RecyclerView,将布局设置为GridLayoutManager时,发现高度设置为wrap_content无效: 描述 Google一下后,结果如下。

RecyclerView并不负责Item的显示工作,而Adapter负责的是数据仓库和Item的视图,所以最终把目标锁定到RecyclerView.LayoutManager上。于是尝试继承LinearLayoutManager,发现果然有onMeasure方法。

类名 说明
RecyclerView.Adapter 托管数据集合,为每个Item创建视图
RecyclerView.ViewHolder 承载Item视图的子视图
RecyclerView.LayoutManager 负责Item视图的布局
RecyclerView.ItemDecoration 为每个Item视图添加子视图,在Demo中被用来绘制Divider
RecyclerView.ItemAnimator 负责添加、删除数据时的动画效果

于是自定义MyGridLayoutManager,继承自GridLayoutManager,重写onMeasure方法:

@Override
    public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state, int widthSpec, int heightSpec) {
        int height = 0;
        int childCount = getItemCount();
        for (int i = 0; i < childCount; i++) {
            View child = recycler.getViewForPosition(i);
            measureChild(child, widthSpec, heightSpec);
            if (i % getSpanCount() == 0) {
                int measuredHeight = child.getMeasuredHeight() + getDecoratedBottom(child);
                height += measuredHeight;
            }
        }
        setMeasuredDimension(View.MeasureSpec.getSize(widthSpec), height);
    }

此时,RecyclerView便可显示实际高度: 完整代码如下:

package com.sunflower.music.recyclerview;

import android.content.Context;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.StaggeredGridLayoutManager;
import android.util.Log;
import android.view.View;

/**
 * Created by sunflower on 2015/8/30.
 */
public class MyGridLayoutManager extends GridLayoutManager {
    public MyGridLayoutManager(Context context, int spanCount) {
        //默认方向是VERTICAL
        super(context, spanCount);
    }

    public MyGridLayoutManager(Context context, int spanCount, int orientation, boolean reverseLayout) {
        super(context, spanCount, orientation, reverseLayout);
    }

    @Override
    public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state, int widthSpec, int heightSpec) {
        int height = 0;
        Log.i("msg", "onMeasure---MeasureSpec-" + View.MeasureSpec.getSize(heightSpec));
        int childCount = getItemCount();
        for (int i = 0; i < childCount; i++) {
            View child = recycler.getViewForPosition(i);
            measureChild(child, widthSpec, heightSpec);
            if (i % getSpanCount() == 0) {
                int measuredHeight = child.getMeasuredHeight() + getDecoratedBottom(child);
                height += measuredHeight;
            }
        }
        Log.i("msg", "onMeasure---height-" + height);
        setMeasuredDimension(View.MeasureSpec.getSize(widthSpec), height);

    }

}

第二个构造函数参数reverseLayout的含义是什么呢?官方文档是这么说明的:

When set to true, layouts from end to start.

实践是检验真理的唯一标准,当设置为true后,效果如下: 可以看到“心情”下面的排列顺序由0~15的递增顺序变为递减了,所以当reverseLayout设置为true时,会将Adapter对应的内容倒着显示

本文中的表格来自Android-RecylerView初识

AllenVork commented 8 years ago
for (int i = 0; i < childCount; i++) {
            View child = recycler.getViewForPosition(i);

这里我的childCount = 7 但getViewForPosition(0)出现:

java.lang.IndexOutOfBoundsException: Invalid item position 0(0). Item count:0
at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:4604)
herohd commented 8 years ago

java.lang.IndexOutOfBoundsException: Invalid item position 0(0). Item count:0 getViewForPosition 数组越界,

herdotage commented 7 years ago

java.lang.IndexOutOfBoundsException: Invalid item position 0(0). Item count:0 getViewForPosition 数组越界,

471448446 commented 7 years ago

@AllenVork

mLayoutManager.setAutoMeasureEnabled(false)
recyclerView.setHasFixedSize(false)
fishone commented 7 years ago

你这个页面的布局,能给我一份吗!