在 RecyclerView 中显示原生广告

Sum*_*iya 3 android ads android-layout native-ads

我正在使用 RecyclerView。其中我必须在 GridLayout Manager 中显示两个项目,并且跨度计数为 2,才能以全宽显示原生广告。谁能帮我。输出如图 1 所示

我需要的实际输出如图2

Mar*_*ini 6

2022 年 7 月更新

示例项目已更新为最新的依赖项。

有人还问“如果我想在运行时根据用户选择的布局管理器来交换布局管理器怎么办?” 没问题,检查更新的分支。没有魔法。

原答案

我想我已经找到了一个可能适合您的解决方案。我在这里使用 Kotlin,但我确信用 Java 也可以实现同样的效果。

假设

  • 您正在使用GridLayoutManager
  • 您想要每 N 个项目插入一个“广告”。
  • 您已经实现或有方法来确定您显示的数据类型(又名:您根据 itemType 膨胀不同的“ViewHolders”)。
  • 在不可变数据列表中插入占位符不会出现问题,因此您的 RecyclerView 适配器不会充满疯狂的逻辑,并且您的 GridLayout 也不必是自定义的。

如何?

  • 网格布局管理器根据“跨度”的数量(我在心里将其称为“列”,即使这实际上并不是这个意思)来计算布局/度量。
  • 当您创建 GridLayoutManager 时,您可以通过提供布局将跨越的跨度数来实现这一点(哈哈?)
  • 可以更改视图在网格中布局时跨度数(?) 。默认情况下,视图将跨越一个跨度(跨度已经足够了)。

“跨度”这个词就够了……

假设您有一个List<Thing>作为数据源。你有 0..n件东西。SaidThing具有通过 Type 进行识别的方法。又名:aThing.type. 假设你有两种类型:

正常和AD。

enum Type { Normal, AD }
Run Code Online (Sandbox Code Playgroud)

(例如)。

所以你可以这样做:

if (thing.type == Type.AD)
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

因此,我们根据原始列表返回一个 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())
  }

Run Code Online (Sandbox Code Playgroud)

这看起来像您的初始网格。

现在,一开始我想,如果我们创建一个自定义的 LayoutManager,它“智能”地知道何时显示广告等。

但后来我发现GridLayoutManager 智能地公开了一个值(并且它有效):

spanSizeLookup:设置source获取adapter中每一项占用的span数量。

这正是我们所需要的,告诉网格:嘿,这个项目占据了 N 个跨度,但是另一个项目占据了 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
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

瞧!

由于需要处理的内容很多,因此我创建了一个示例项目来展示其实际情况。它有一个错误,希望您能发现它(并修复它!):)

注意我没有使用任何 AD 加载库,这取决于你。请记住,广告通常以 WebView 的形式实现,因此往往会很慢、异步等。准备好在广告尚未加载时显示占位符等。这实际上取决于您如何实现这一方面,天空是最重要的限制。这只是我为了测试我的理论而构建的一个简单示例。

我个人认为这会更难;我证明自己错了。

祝你好运。