簡體   English   中英

在 RecyclerView 中顯示原生廣告

[英]Showing Native Ads in RecyclerView

我正在使用 RecyclerView。 其中我必須在 GridLayout Manager 中顯示兩個項目,並且跨度計數為 2 以顯示全寬的原生廣告。 誰能幫我。 輸出如圖 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.

在活動中:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM