【问题标题】:RecyclerView - Continuous Columns LayoutRecyclerView - 连续列布局
【发布时间】:2020-10-19 22:40:07
【问题描述】:

我正在尝试创建一个布局,其中项目将在列中彼此跟随(见下图),但我还没有到达那里。我已经尝试过GridLayoutManagerStaggeredGridLayoutManager - 两者的问题都没有提供项目流入另一列并以这种方式相互跟随的特性。根据我目前的尝试,我正在尝试FlexboxLayoutManager,但我得到的结果总是带有单个项目的列,而不是一个接一个地流动的项目。

期望的行为是项目一个接一个地定位,当回收器的高度不允许完整的项目视图时,它应该被分解到下一列。

这是我现在正在尝试的:

mBinding?.activeRecycler?.layoutManager = FlexboxLayoutManager(context).apply {
            flexDirection = FlexDirection.COLUMN
            flexWrap = FlexWrap.WRAP
            alignItems = AlignItems.STRETCH
        }

这让我每列有一个项目。

正在努力实现这一目标:

【问题讨论】:

  • StaggeredGridLayoutManager?
  • 编辑了问题,StaggeredGridLayoutManager 没有提供我正在寻找的内容 - 特别是如果高度较大,项目会流向下一列
  • 一个 LayoutManager 应该如何将一个项目分成两部分,就像项目 3 的图形一样?它只能从布局的角度来操作现有的项目。您能否更具体地说明您正在显示的内容类型以及在中间拆分时的外观(如第 3 项)?
  • @ymindstorm 我正在显示一张带有多个文本字段的卡片,它看起来应该到达窗口底部并继续下一列,就好像它流入第二列一样。是的,我知道布局管理器可以操纵一个项目,所以如果高度大于窗口允许的高度(如项目 3),我想操纵现有项目以显示在 2 列上。
  • 布局管理器可以是自定义解决方案,也可以是任何允许使用回收站视图的解决方案

标签: android android-layout android-recyclerview


【解决方案1】:

我非常怀疑这是可能的。 RecyclerView、它的适配器和它的布局管理器都不是为了改变视图的基本形式而设计的。

意思是“拆分”一个是不可能的。 RecyclerView 旨在了解同时有多少视图,只创建这些视图,然后将底层对象分别绑定到视图。

意味着 RecyclerView 不会“将视图切成两半并在不同的地方显示它的两半”。

如果布局管理器专门设计为在多个视图中显示一个项目,从而在多个位置中显示一个项目,那么像您这样的星座是可能的唯一方法。这将允许它按照您的描述显示。然而,正如我所说,这意味着中间的视图3 和最后一列的视图3 将是绑定到同一个对象或其副本的两个视图。 (或者有人完全疯了,实际上分裂了观点,我对此表示怀疑)。

我不相信任何标准布局管理器都能够做到这一点,我怀疑您甚至可以在不相应地更改适配器的情况下实现这一点,至少。因为适配器基本上完成了绑定,所以如果没有它的帮助,标准布局管理器将无法进行上述双重绑定。

话虽如此,这只是一个很好的猜测,根据视图及其组件的原理。我没有阅读每个布局管理器的源代码或完整描述。

【讨论】:

  • 是的,我正在考虑将视图拆分为 2 并使用相同的 id 绑定来定义它是同一个对象,因为它不是显示问题,而是处理点击事件。
  • 没错。因此,使用通常的布局管理器进行拆分基本上是不可能的,即使您设法将这种行为破解到它们中,我怀疑这是否会自动意味着您可以像往常一样处理视图。
  • 但我什至找不到可以提供从左到右的垂直列来拆分视图的布局管理器。好像没有人尝试在 Android 中实现这一目标
  • 正确,所以我猜你必须自己构建它。布局管理器和适配器,甚至是一个全新的视图。也许是多个 RecyclerViews 的组合。无论如何,这可能会非常困难并且超出任何合理的 SO 答案
  • 一些答案​​确实有相当多的代码并且回答了相当困难的问题,尤其是在赏金部分。所以我有希望:)
【解决方案2】:

我理解您的问题的方式是这样的:您拥有当前包含文本字段的数据列表,并且您希望以正常方式显示它们,一个列表项一个视图项在回收站视图中。

但根据您的设计要求,这是不可能的。

我的想法是这样的: 您必须创建一个新列表,将前一个列表中的一个项目分成 2,3 个或更多项目以适合您的列。

private fun demo() {

    val originalList = listOf<String>()
    val newScreenSpecificList = mutableListOf<String>()

    val columnHeight = 3//example number of lines
    val columnWidth = 10//example number of chars
    var columnsIndex = 0//index of column
    var currentColumnHeight = 0 // current column filled height

    originalList.forEach {
        if (currentColumnHeight + getTextHeight(it, columnWidth) <= columnHeight) {
            newScreenSpecificList.add(it)
            currentColumnHeight = currentColumnHeight + getTextHeight(it, columnWidth)
        } else {
            //here is the part where your text is bigger then your column height so you need to divide it
            val textForSpaceLeft = getTextForSpaceLeft(it, columnHeight - currentColumnHeight)
            newScreenSpecificList.add(textForSpaceLeft)
            currentColumnHeight = currentColumnHeight + getTextHeight(textForSpaceLeft, columnWidth)

            if (currentColumnHeight >= columnHeight) {
                columnsIndex++
            }

            if (getTextForNewSpaceLeft(it, columnHeight - currentColumnHeight)){
                //continue to repeat logic for new column
                //...
            }

        }

        if (currentColumnHeight >= columnHeight) {
            columnsIndex++
        }
    }

}

private fun getTextForSpaceLeft(it: String, spaceLeft: Int): String {
    return "it"// return text for the available space
}

private fun getTextForNewSpaceLeft(it: String, spaceLeft: Int): String {
    return "new column also"// return text left for the new available space
}

private fun getTextHeight(text: String, columnWidth: Int): Int {
    return 2//todo your logic to convert text length to number of lines needed for a specific width of the column
}

现在你需要继续这个逻辑它不完整,我希望它可以帮助你。

【讨论】:

  • 感谢您的回答,当高度不适合它时,看起来一切都会将项目分解为多个项目并将块移动到新列,我明白这一点逻辑需要做更多的工作。
【解决方案3】:

我猜您的问题在于适配器中正在创建的项目的LayoutParams。可能项目中的高度设置为match_parent。您可以尝试更改适配器的onCreateViewHolder/onBindViewHolder 中 itemViews 的LayoutParams。或者如果项目的高度很难计算,您可以创建一个 customView 并尝试在 onMeasure 中计算高度并将高度设置为wrap_content

尝试将项目的高度设置为wrap_content,或者如果你想在代码中这样做,如下所示:

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FlexItemViewHolder {
    val infatedView = ...
    
    infatedView.layoutParams = FlexboxLayoutManager.LayoutParams(FlexboxLayoutManager.LayoutParams.WRAP_CONTENT,     FlexboxLayoutManager.LayoutParams.WRAP_CONTENT)
    infatedView.addView(textView)
    return FlexItemViewHolder(f)
}

【讨论】:

  • 当项目太长时,这对流入下一列有何帮助?
  • 高度是wrap_content,问题是wrap_content可能大于整个屏幕高度。
猜你喜欢
  • 1970-01-01
  • 2011-08-13
  • 1970-01-01
  • 2021-05-04
  • 1970-01-01
  • 1970-01-01
  • 2016-09-05
  • 2020-10-14
  • 2016-05-28
相关资源
最近更新 更多