在RecyclerView中显示原生广告

时间:2019-06-10 11:40:35

标签: android android-layout ads native-ads

我正在使用RecyclerView。在其中,我必须在GridLayout Manager中显示两个项目,并且跨度计数为2,才能显示全宽度的原生广告。谁能帮我。Output coming like image 1

Actual Output I need like image 2

2 个答案:

答案 0 :(得分:0)

我想我已经找到了可能适合您的解决方案。我在这里使用Kotlin,但是我敢肯定,在Java中也可以实现同样的目的。

假设

  • 您正在使用GridLayoutManager
  • 您要每N个项目插入一个“广告”。
  • 您已实施或有方法确定要显示的数据类型(aka:根据itemType为不同的“ ViewHolders”充气。
  • 您不会在不可变数据列表中插入占位符,因此RecyclerView适配器不会充满疯狂的逻辑,而且GridLayout不必自定义。

如何?

  • 一个Grid布局管理器,根据“ spans”(即使在我看来,这并不是真正的意思是“ Columns”)的数量来计算布局/度量。
  • 创建GridLayoutManager时,通过提供所述布局的跨度数可以做到 span (大声笑?)
  • 可以更改在网格中放置视图时跨度(?)的跨度数(?)。默认情况下,视图将跨度为一个跨度(对于 span somethingy 已经足够了)。

“ Span”一词已足够...

假设您有一个List<Thing>作为数据源。 您有0..n个事物。 所述Thing具有通过类型标识的手段。 aka: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(这只是一种实现方式,不是唯一的方法,当然也不是所有情况下的最佳方法,它可能不仅仅令人眼花)乱。) / p>

什么是AdPlaceholder()

这只是专门的“事物”:)(见下文)。

现在在您的活动/片段中的某个位置,您可能会像这样设置recyclerview :(再次,伪代码,但有效的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,它“智能”地显示何时显示广告以及不显示什么。

但是后来我发现GridLayoutManager智能地公开了一个(并且它可以工作):

  

spanSizeLookup:设置源以获取适配器中每个项目占用的跨度数。

这正是我们需要告知网格的内容:嘿,此项目占用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
        }
    }
}

还有瞧!

由于要处理的工作量很大,因此我创建了a sample project来说明实际情况。它有一个错误,希望您可以发现它(并修复它!):)

请注意,我没有使用任何AD加载库,这取决于您。请注意,广告通常以WebView的形式实现,因此通常会变得缓慢,异步等。准备好在广告尚未加载时显示占位符,等等。 这实际上取决于您如何实现事物的这一方面,而天空是极限。这只是我用来检验理论的简单样本。

我个人认为这将变得更加困难;我证明自己错了。

祝你好运。

答案 1 :(得分:0)

活动中:

StaggeredGridLayoutManager layoutManager = new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL);
recyclerView.setLayoutManager(layoutManager);
recyclerView.setHasFixedSize(true);
recyclerView.setAdapter(mAdapter);

在您的回收站 OnCreateViewHolder 中:

switch (viewType) {

       ...........      

       case TYPE_AD: {
            View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.AD_ITEM_LAYOUT, parent, false);
            final ViewGroup.LayoutParams lp = v.getLayoutParams();
                if (lp instanceof StaggeredGridLayoutManager.LayoutParams){
                    StaggeredGridLayoutManager.LayoutParams sglp = (StaggeredGridLayoutManager.LayoutParams)lp;
                    sglp.setFullSpan(true);
                }
                return new AdViewHolder(v);
            }

       ...........

}

并在 getItemViewType 方法中计算服务 TYPE_AD :

@Override
    public int getItemViewType(int position) {

       .........

       if (position % 4 == 0){
          return TYPE_AD;
       }

       .........
    }