[英]Showing Native Ads in RecyclerView
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.
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.
GridLayoutManager
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.