简体   繁体   English

在 RecyclerView 中显示原生广告

[英]Showing Native Ads in RecyclerView

I am working with RecyclerView.我正在使用 RecyclerView。 In which I have to show two items in GridLayout Manager and span count of 2 to display native ads with full width.其中我必须在 GridLayout Manager 中显示两个项目,并且跨度计数为 2 以显示全宽的原生广告。 Can anyone help me.谁能帮我。 输出如图 1

我需要的实际输出,如图 2

Update July 2022

The Sample Project has been updated to latest Dependencies.

Someone also asked "what if I want to swap the layout manager at runtime based on the user choosing one?" No problem, check the updated branch. There's no Magic.

Original Answer

I think I have found a solution that may work for you. I am using Kotlin here but I'm sure the same can be achieved in Java.

Assumptions

  • You are using GridLayoutManager
  • You want to insert an "ad" every N number of items.
  • You have implemented or have ways to determine what TYPE of data you're showing (aka: you inflate different "ViewHolders" based on the itemType.
  • You don't have problems inserting placeholders in your list of immutable data so your RecyclerView adapter is not full of crazy logic and also your GridLayout doesn't have to be custom.

How?

  • A Grid layout manager, calculates the layouts/measures depending upon the number of "spans" (which I mentally refer to as Columns, even if this doesn't really mean that).
  • When you create a GridLayoutManager, you do so, by providing the number of spans said layout will span (lol?)
  • It is possible to change the number of spans(?) a view will span when laid out in the grid. By default, views will span ONE span (ok enough with the span thingy already).

Enough with the "Span" word...

Say you have a List<Thing> as your data source. You have 0..n things. Said Thing has means to be identified by Type. aka: aThing.type. Imagine you have two types:

Normal and AD.

enum Type { Normal, AD }

(for example).

so you can do:

if (thing.type == Type.AD)

Now I assume you receive a list of Thing from your repository.

You have different options (I'll explore only one, and leave others as an exercise to the reader, primarily because I don't have that much time, but also because each best solution will really depend on the context. I don't have much context here). My requirement is simple: make the ads span all the grid.

A simple solution involves mutating the list of results your Repository gives you (note, I would not touch the repo's data, make a copy, use the copy for your adapter).

So when you get your list, instead of sending it directly to the adapter, modify it:

(this is pseudo code, assuming listOfData is the data you want to show, already populated of course)

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

So we return a newList based off of the original list (this is just a way of doing it, not the only one and certainly not the best one in all contexts, there may be much more than meet the eye).

What is AdPlaceholder() ?

It's just a specialized "Thing" :) (see below).

Now somewhere in your activity/fragment you probably set up your recyclerview like so: (again, pseudo code, but valid 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())
  }

This would look like your initial grid.

Now, at first, I thought, what if we create a custom LayoutManager that is "intelligent" about when to display ads and whatnot.

But then I found that there's a value that is intelligently exposed by the GridLayoutManager (and that it works):

spanSizeLookup: Sets the source to get the number of spans occupied by each item in the adapter.

This is exactly what we need, to tell the Grid: hey, this item occupies N spans, but this other item occupies Y.

So, I added this:

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
        }
    }
}

And Voila!

Since this is a lot to process, I've created a sample project that shows this in action. It has a bug, hopefully you can spot it (and fix it!) :)

Note I did not use any AD loading library, that's up to you. Keep in mind ads are usually implemented as WebViews and therefore tend to be slow, asynchronous, etc. Be prepared to show placeholders when the ad hasnt loaded yet, etc. It will really depend how you implement that side of things, the sky is the limit. This has just been a simple sample I built to test my theory.

I personally thought this was going to be harder; I proved myself wrong.

Good luck.

In Activity:在活动中:

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

In your recycler adpater OnCreateViewHolder :在您的回收站适配器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); }........... }

and do calculation for serving TYPE_AD in getItemViewType method:并在getItemViewType方法中计算服务 TYPE_AD:

 @Override public int getItemViewType(int position) {......... if (position % 4 == 0){ return TYPE_AD; }......... }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM