当前位置: 首页 > 知识库问答 >
问题:

RecyclerView GridLayoutManager:如何自动检测跨度计数?

羊煜
2023-03-14

使用新的GridLayoutManager:https://developer.android.com/reference/android/support/v7/widget/GridLayoutManager.html

它需要一个明确的跨度计数,所以现在的问题是:如何知道每行适合多少“跨度”?毕竟,这是一个网格。根据测量的宽度,RecyclerView应该有尽可能多的跨度。

使用旧的GridView,只需设置“columnWidth”属性,它就会自动检测适合的列数。这就是我想为RecyclerView复制的内容:

  • 添加OnLayoutChangeListener在RecyClaire View
  • 在这个回调中,膨胀一个网格项并测量它
  • spanCount=回收器ViewWidth/SingleItemWidth;

这似乎是很常见的行为,所以有没有一种更简单的方式,我没有看到?

共有3个答案

百里君博
2023-03-14

这是我用过的,非常基本,但能帮我完成任务。这段代码基本上得到了屏幕的宽度(以倾角为单位),然后除以300(或者适配器布局使用的任何宽度)。因此,300-500下倾宽度的小型手机只显示一列,平板电脑显示2-3列等。就我所见,简单、无需大惊小怪,没有负面影响。

Display display = getActivity().getWindowManager().getDefaultDisplay();
DisplayMetrics outMetrics = new DisplayMetrics();
display.getMetrics(outMetrics);

float density  = getResources().getDisplayMetrics().density;
float dpWidth  = outMetrics.widthPixels / density;
int columns = Math.round(dpWidth/300);
mLayoutManager = new GridLayoutManager(getActivity(),columns);
mRecyclerView.setLayoutManager(mLayoutManager);
宋洲
2023-03-14

我使用视图树观察者完成了这一点,一旦呈现就获得recylcerview的宽度,然后从资源中获得我的卡片视图的固定尺寸,然后在计算后设置跨度计数。只有当您显示的项目具有固定宽度时,它才真正适用。这帮助我自动填充网格,而不管屏幕大小或方向如何。

mRecyclerView.getViewTreeObserver().addOnGlobalLayoutListener(
            new ViewTreeObserver.OnGlobalLayoutListener() {
                @Override
                public void onGlobalLayout() {
                    mRecyclerView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
                    int viewWidth = mRecyclerView.getMeasuredWidth();
                    float cardViewWidth = getActivity().getResources().getDimension(R.dimen.cardview_layout_width);
                    int newSpanCount = (int) Math.floor(viewWidth / cardViewWidth);
                    mLayoutManager.setSpanCount(newSpanCount);
                    mLayoutManager.requestLayout();
                }
            });
梁英喆
2023-03-14

就个人而言,我不喜欢为此将RecyclerView子类化,因为对我来说,GridLayoutManager似乎有责任检测跨度计数。因此,在为RecyclerView和GridLayoutManager挖掘了一些android源代码之后,我编写了自己的类扩展GridLayoutManager,用于完成这项工作:

public class GridAutofitLayoutManager extends GridLayoutManager
{
    private int columnWidth;
    private boolean isColumnWidthChanged = true;
    private int lastWidth;
    private int lastHeight;

    public GridAutofitLayoutManager(@NonNull final Context context, final int columnWidth) {
        /* Initially set spanCount to 1, will be changed automatically later. */
        super(context, 1);
        setColumnWidth(checkedColumnWidth(context, columnWidth));
    }

    public GridAutofitLayoutManager(
        @NonNull final Context context,
        final int columnWidth,
        final int orientation,
        final boolean reverseLayout) {

        /* Initially set spanCount to 1, will be changed automatically later. */
        super(context, 1, orientation, reverseLayout);
        setColumnWidth(checkedColumnWidth(context, columnWidth));
    }

    private int checkedColumnWidth(@NonNull final Context context, final int columnWidth) {
        if (columnWidth <= 0) {
            /* Set default columnWidth value (48dp here). It is better to move this constant
            to static constant on top, but we need context to convert it to dp, so can't really
            do so. */
            columnWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 48,
                    context.getResources().getDisplayMetrics());
        }
        return columnWidth;
    }

    public void setColumnWidth(final int newColumnWidth) {
        if (newColumnWidth > 0 && newColumnWidth != columnWidth) {
            columnWidth = newColumnWidth;
            isColumnWidthChanged = true;
        }
    }

    @Override
    public void onLayoutChildren(@NonNull final RecyclerView.Recycler recycler, @NonNull final RecyclerView.State state) {
        final int width = getWidth();
        final int height = getHeight();
        if (columnWidth > 0 && width > 0 && height > 0 && (isColumnWidthChanged || lastWidth != width || lastHeight != height)) {
            final int totalSpace;
            if (getOrientation() == VERTICAL) {
                totalSpace = width - getPaddingRight() - getPaddingLeft();
            } else {
                totalSpace = height - getPaddingTop() - getPaddingBottom();
            }
            final int spanCount = Math.max(1, totalSpace / columnWidth);
            setSpanCount(spanCount);
            isColumnWidthChanged = false;
        }
        lastWidth = width;
        lastHeight = height;
        super.onLayoutChildren(recycler, state);
    }
}

我真的不记得为什么我选择在onLayoutChildren中设置跨度计数,我不久前写过这个课程。但关键是,我们需要在衡量观点之后这样做。所以我们可以得到它的高度和宽度。

编辑1:修复因错误设置量程计数而导致的代码错误。感谢用户@Elyees Abouda的报告和建议解决方案。

编辑2:一些小的重构和修复边缘的情况下,手动方向的变化处理。感谢user@tatarize的报告和建议解决方案。

 类似资料:
  • 脚本例子一: !include "MUI.nsh" OutFile "S32.exe" !define MUI_PAGE_CUSTOMFUNCTION_PRE ComponentsPage1Pre !insertmacro MUI_PAGE_COMPONENTS Sectiongroup "完整独立程序" SecOL3 Section /o "QQ直播程序" Sec60 Sectio

  • 问题内容: 是否可以使用加速度计检测高度?例如,如果我手持手机,然后举起手臂来检测身高? 谢谢 问题答案: 假设您的意思是要检测手机从其凝视点起的高度,是的。android加速度计可测量力,有关如何使用它的更多信息,请参见此处 。请记住,加速度计并不是一个完美的设备,因此您的结果将是手机实际移动了多少的近似值。

  • 问题内容: 嗨,我正在创建一个Web应用程序,如果用户注册,我们将在其中显示创建日期。 为此,我们在sql表中使用当前时间戳记,其中显示了服务器时间,但是我们不知道如何根据用户时区转换时间。 因为我们没有 得到用户所在的国家 。 可以帮我解决这个问题吗 提前致谢 :) 问题答案: 使用JavaScript解决方案 http://www.onlineaspect.com/2007/06/08/aut

  • 我很肯定我过去在JPA2.0中使用了某种自动检测用@Entity注释的bean的方法,但我无法弄清楚是如何实现的。如何做到这一点,而不是在persistence.XML中列出XML元素中的每个bean?

  • 问题内容: 我可以肯定的是,过去我在JPA 2.0中使用了某种自动检测带有@Entity注释的bean的方法,但是我无法找到方法。您如何做到这一点,而不是在persistence.xml 的XML元素中列出每个bean ? 问题答案: 从Spring 3.1开始,您还可以选择完全忘记persistence.xml,并使用属性进行配置,如下所示:

  • 我正在开发一个运行在PC上的Java测试控制器应用程序。它有: 在android手机上安装应用程序: 怎么做有什么想法吗?