我想我找到了可能对您有用的解决方案。我在这里使用 Kotlin,但我确信在 Java 中也可以实现。
假设
- 您正在使用
GridLayoutManager
- 您希望每 N 个项目插入一个“广告”。
- 您已经实现或有方法来确定您要显示的数据类型(又名:您根据 itemType 膨胀不同的“ViewHolders”。
- 在不可变数据列表中插入占位符没有问题,因此您的 RecyclerView 适配器不会充满疯狂的逻辑,而且您的 GridLayout 也不必是自定义的。
如何?
- 一个网格布局管理器,根据“跨度”的数量计算布局/度量(我在心理上将其称为列,即使这并不是真正的意思)。
- 当您创建 GridLayoutManager 时,您会这样做,通过提供表示布局将 span 的跨度数(哈哈?)
- 可以更改视图在网格中布局时的跨度数(?)跨度。默认情况下,视图将跨越一个跨度(span thingy 已经足够了)。
“跨度”这个词就够了……
假设您有一个List<Thing> 作为您的数据源。
你有 0..n 东西。
说Thing有通过Type来识别的意思。又名:aThing.type。
假设你有两种类型:
正常和 AD。
enum Type { Normal, AD }
(例如)。
所以你可以这样做:
if (thing.type == Type.AD)
现在我假设您从您的存储库中收到了Thing 的列表。
你有不同的选择(我只探索一个,其他的留给读者作为练习,主要是因为我没有那么多时间,而且每个最佳解决方案都会真的取决于上下文。我这里没有太多上下文)。我的要求很简单:让广告跨越所有网格。
一个简单的解决方案涉及改变存储库为您提供的结果列表(请注意,我不会接触存储库的数据,制作副本,将副本用于适配器)。
所以当你得到你的列表时,不要将它直接发送到适配器,而是修改它:
(这是伪代码,假设listOfData是你要显示的数据,当然已经填充了)
var newList = ArrayList<Thing>()
for ((index, thing) in listOfData.withIndex()) {
// if it's an Ad, insert one, and continue adding items
if (index % 4 == 0) {
newList.add(AdPlaceholder())
} else {
newList.add(thing)
}
}
return newList
所以我们根据原始列表返回一个 newList(这只是一种实现方式,不是唯一的,当然也不是所有情况下最好的,可能远不止眼前所见)。
AdPlaceholder() 是什么?
这只是一个专门的“东西”:)(见下文)。
现在在您的活动/片段中的某个地方,您可能会像这样设置您的回收站视图:(再次,伪代码,但有效的 Kotlin)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
layoutManager = GridLayoutManager(this, 2)
mainRecyclerView.layoutManager = layoutManager
mainRecyclerView.adapter = YourAdapter()
// and somewhere you'll send data to this adapter...
adapter.submitList(repository.getMyListOfThings())
}
这看起来像您的初始网格。
现在,起初,我想,如果我们创建一个自定义 LayoutManager,它可以“智能”了解何时显示广告等等。
但后来我发现有一个 value 被 GridLayoutManager 智能公开(并且它有效):
spanSizeLookup:设置源获取适配器中每个项目占用的span数。
这正是我们需要的,告诉 Grid:嘿,这个 item 占据了 N spans,但是这个 item 占据了 Y。
所以,我添加了这个:
layoutManager.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {
override fun getSpanSize(position: Int): Int {
return when (adapter.getItemViewType(position)) {
adapter.normalViewType -> 1
adapter.adViewType -> 2
else -> 1 //default
}
}
}
瞧!
由于要处理的内容很多,我创建了a sample project 来展示这一点。它有一个错误,希望你能发现它(并修复它!):)
注意我没有使用任何广告加载库,这取决于你。请记住,广告通常以 WebView 的形式实现,因此往往很慢、异步等。准备好在广告尚未加载时显示占位符等。
这真的取决于你如何实现这方面的事情,天空才是极限。这只是我为测试我的理论而构建的一个简单示例。
我个人认为这会更难;我证明自己错了。
祝你好运。