根据项目位置动态更改 StaggeredGridLayout 的列跨度计数

Posted

技术标签:

【中文标题】根据项目位置动态更改 StaggeredGridLayout 的列跨度计数【英文标题】:Change column span count of StaggeredGridLayout dynamically based on item position 【发布时间】:2019-11-11 23:10:55 【问题描述】:

我想为 (n) 个项目列表实现这种布局:

到目前为止,我可以在两列中显示项目,但是如何将两列合并为一列以用于特定位置(即作为项目 7)?

我尝试了 SO 和其他提供的许多解决方案,但没有一个对我有用。那里提供的解决方案要么使用 LinearLayout 膨胀静态布局,要么提供在列中进行分区的解决方案。

我也尝试过使用setSpanLookup 方法但没有运气..

【问题讨论】:

建议没问题,如果您想查看“假工作样本”,我必须为广告支持的网格做这件事,所以我创建了一个原型 here。更具体地说,执行此操作的“适配器”位于同一 repo 中,here。话虽如此,我使用的是 GridLayout,而不是交错版本。 @MartinMarconcini 我已经尝试过您的代码并且工作正常.. 但也请查看我的解决方案。这听起来更理想。我想..你对此有何看法... 我看到了;老实说,我不是一个忠实的粉丝。您正在手动触摸布局参数并将显示内容的责任委托给您的活动。如果它对您有用,那很好,但我不会依赖“附加到窗口的视图”来决定显示什么/如何显示某些内容。我不知道,也许其他人看到并认为这很好;我不会想到使用这种方法。这是一个演示问题。在您的示例中,您将业务逻辑置于生命周期方法中,不易测试,不易更改,不易查找或扩展等。 /shrug 【参考方案1】:

经过彻底的努力,终于找到了对我有用的解决方案:

    @Override
        public void onViewAttachedToWindow(MyViewHolder holder) 
            super.onViewAttachedToWindow(holder);
            ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams();
            if(lp != null
                    && lp instanceof StaggeredGridLayoutManager.LayoutParams
                    && (holder.getLayoutPosition() == 6 || holder.getLayoutPosition() == 13)) 
                StaggeredGridLayoutManager.LayoutParams p = (StaggeredGridLayoutManager.LayoutParams) lp;
                p.setFullSpan(true);
            
           holder.setIsRecyclable(false);
        

希望这对你也有帮助。

【讨论】:

【参考方案2】:

正如你所说,我认为setSpanLookup 是最好的方法。

试试这个代码:

class MainActivity : AppCompatActivity() 

    override fun onCreate(savedInstanceState: Bundle?) 
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val layoutManager = GridLayoutManager(this, 2)
        layoutManager.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() 
            override fun getSpanSize(position: Int): Int 
                if (position == 6 || position == 13) return 2
                else return 1
            
        
        rv.layoutManager = layoutManager

        val items = mutableListOf<String>()
        for (i in 1..14) 
            items.add("item$i")
        
        rv.adapter = MyAdapter(items)
    

您需要知道返回的值getSpanSize 表示重量,而不是列数。

在item布局方面,可以在特殊位置使用不同的ViewHolder。

例如:

companion object
    const val NORMAL = 0
    const val WIDE = 1


override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder 
    ...
    if (viewType == WIDE) return WideViewHolder(wideView)
    else return NormalViewHolder(normalView)


override fun getItemViewType(position: Int): Int 
    if (position == 6 || position == 13) 
        return WIDE
    
    return NORMAL

【讨论】:

【参考方案3】:

只需创建一个表: 在您的情况下是 8 行和 3 列,设置边界线和边界对齐,项目 7 和 14 将占用 3 个单元格。这是一个例子:

private void insertCell(PdfPTable table, String text, int align, int colspan, Font font) 

    //create a new cell with the specified Text and Font
    PdfPCell cell = new PdfPCell(new Phrase(text.trim(), font));
    //set the cell alignment
    cell.setHorizontalAlignment(align);
    //set the cell column span in case you want to merge two or more cells
    cell.setColspan(colspan);
    //in case there is no text and you wan to create an empty row
    if (text.trim().equalsIgnoreCase("")) 
        cell.setMinimumHeight(10f);
    
    //add the call to the table
    table.addCell(cell);

【讨论】:

以上是关于根据项目位置动态更改 StaggeredGridLayout 的列跨度计数的主要内容,如果未能解决你的问题,请参考以下文章

根据屏幕大小动态更改元素位置

如何根据 y 位置动态更改标记点的颜色

如何根据位置更改listView项目的颜色

如何动态更改 UIButton 的位置

如何根据从外部传递的更改值动态更改自定义小部件中成员的值

UITabbarController 动态更改项目