RecyclerView - 连续列布局

问题描述 投票:0回答:4

我正在尝试创建一种布局,其中项目将在列中相互跟随(见下图),但我还没有到达那里。我尝试过

GridLayoutManager
StaggeredGridLayoutManager
- 两者的问题都没有提供项目流入另一列并以这种方式相互跟随的功能。在我当前的尝试中,我正在尝试
FlexboxLayoutManager
,但我得到的结果始终是包含单个项目的列,而不是一个接一个地流动的项目。

所需的行为是项目一个接一个地定位,当回收器的高度不允许完整项目视图时,应将其分解到下一列。

这是我现在正在尝试的:

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

这让我每列一个项目。

努力实现这一目标:

enter image description here

android android-layout android-recyclerview
4个回答
1
投票

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

这意味着“分裂”是不可能的。 RecyclerView 旨在了解同时看到有多少个视图,仅创建那么多视图,然后分别将底层对象绑定到这些视图。

这意味着 RecyclerView 不会“将视图切成两半并将其两半显示在不同的位置”。

像您这样的星座是可能的唯一方法是布局管理器专门设计为在多个视图中显示一个项目,从而在多个位置中显示一个项目。然后它就可以按照您所描述的方式显示。然而,正如我所说,这意味着中间的视图

3
和最后一列中的视图
3
将是绑定到同一对象或其副本的两个视图。 (或者有人完全疯了,实际上分裂了观点,我对此表示怀疑)。

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

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


1
投票

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

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

我实现这一目标的想法是这样的: 您必须创建一个新列表,它将前一个列表中的一项分成 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
}

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


0
投票

我知道我参加聚会有点晚了,但我很想知道您是否想出了此自定义视图的解决方案?

因为我需要类似的布局,如果您能提供任何帮助,我们将不胜感激。


-1
投票

我猜你的问题在于适配器中创建的项目的

LayoutParams
。可能项目中的高度设置为
match_parent
。您可以尝试更改适配器的
LayoutParams
/
onCreateViewHolder
中 itemView 的
onBindViewHolder
。或者,如果项目的高度计算起来有点棘手,您可以创建一个 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)
}
© www.soinside.com 2019 - 2024. All rights reserved.