今天我尝试在水平方向的回收者视图中实现定制广告。
一切都很好,直到我运行应用程序,并注意到我的MutableList中的一些项目没有显示(或被显示为空白,不知道肯定),并在每一个广告后(只有在广告后)有一个巨大的空白。
我不知道该怎么解决这个问题,我不熟悉适配器内部的多个布局。
适配器声明:
class CardAdapter (val context2: Context, private val Cards:MutableList<Card>) : RecyclerView.Adapter<RecyclerView.ViewHolder>()
这是我的广告持有人内的适配器:
inner class HolderNativeAd(itemView: View): RecyclerView.ViewHolder(itemView){
val app_ad_background : ImageView = itemView.findViewById(R.id.ad_icon)
val ad_headline : TextView = itemView.findViewById(R.id.ad_headline)
val ad_description : TextView = itemView.findViewById(R.id.ad_description)
val ad_price : TextView = itemView.findViewById(R.id.ad_price)
val ad_store : TextView = itemView.findViewById(R.id.ad_store)
val call_to_action : CardView = itemView.findViewById(R.id.ad_call_to_action)
val ad_advertiser : TextView = itemView.findViewById(R.id.ad_advertiser)
val nativeAdView : NativeAdView = itemView.findViewById(R.id.nativeAdView)
fun createAD(context : Context){
val adLoader = AdLoader.Builder(context, context.getString(R.string.native_ad_id_test))
.forNativeAd { nativeAd ->
Log.d(TAG, "onNativeAdLoaded: ")
displayNativeAd(this@HolderNativeAd, nativeAd)
}.withNativeAdOptions(NativeAdOptions.Builder().build()).build()
adLoader.loadAd(AdRequest.Builder().build())
}
}
在创建视图持有者时
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val view: View
if(viewType == VIEW_TYPE_CONTENT){
view = LayoutInflater.from(context2).inflate(R.layout.item_card, parent, false)
return HolderCards(view)
}else{
view = LayoutInflater.from(context2).inflate(R.layout.native_ad_card, parent, false)
return HolderNativeAd(view)
}
}
在绑定视图持有者上
覆盖BindViewHolder上的功能(持有者:循环器视图,取景器,位置:整数){
if (getItemViewType(position) == VIEW_TYPE_CONTENT) {
val model: Card = Cards[position]
(holder as HolderCards).setCard(model, context2)
} else if (getItemViewType(position) == VIEW_TYPE_AD) {
(holder as HolderNativeAd).createAD(context2)
}
}
获取项目视图类型
override fun getItemViewType(position: Int): Int {
//logic to display Native Ad between content
if(position != 0) {
return if (position % 2 == 0) {
//after 2 items, show native ad
VIEW_TYPE_AD
} else {
VIEW_TYPE_CONTENT
}
}
return VIEW_TYPE_CONTENT
}
getitemCount()返回卡片大小
卡可变总数:目前我有一个SingleValueEventListener,它抓取卡片并将它们放入一个mutableList中,为每个项目调用adapter. NotifyItemInserted()。
displayNativeAd(广告载体中使用的自定义方法)
private fun displayNativeAd(holderNativeAd: CardAdapter.HolderNativeAd, nativeAd: NativeAd) {
/* Get Ad assets from the NativeAd Object */
val headline = nativeAd.headline
val body = nativeAd.body
val background = nativeAd.icon
val callToAction = nativeAd.callToAction
val price = nativeAd.price
val store = nativeAd.store
val advertiser = nativeAd.advertiser
...
... (checks to see if a val is null or not)
holderNativeAd.nativeAdView.setNativeAd(nativeAd)
}
2条答案
按热度按时间xmakbtuz1#
好了,系好安全带,因为这是一个很长的问题!实际上是“添加广告”部分使事情变得复杂,而不是额外的
ViewHolder
类型。您丢失了一些项目,因为您要用广告 * 替换 * 其中的一些项目。
Adapter
中的项目总数(itemCount
)应为 * 卡片*的数量加上您要显示的 * 广告 * 的数量。因为您没有处理它,所以使用以下代码实际上跳过了
cards
中的项:你有
cards.size
数量的项目,而不是显示cards[2]
,而是显示一个广告,和cards[2]
从来没有得到显示。(同样,该代码每隔两个项目显示一个广告,position % 2
产生 0 或 1,所以它每隔一个数就循环一次--你需要position % 3
,所以它是3的每一个倍数,但它还有更多的内容,我们会讲到的!)因此,您需要逻辑来处理 * 数据 *(
cards
)和 * 内容 *(cards
+广告)不同的事实:itemCount
需要包含适当数量的广告getItemViewType
需要知道position
是否持有 * 广告 * 或 * 卡 *onBindViewHolder
需要能够将position
转换为cards
中的相应索引让我们先制定规则-假设您希望每三个项目显示一个广告,在前两个项目之后开始,并且您很乐意以广告结束,以使事情简单化。
因此,number of ads 就是有多少组 2 广告-整数除法可以做到这一点:
val adCount = cards.size / 2
项目总数等于项目数加上卡片数:
override fun getItemCount() = cards.size + (cards.size / 2)
判断
position
是一张卡片还是一个广告非常简单,基本上就是你已经做过的事情了!除了我们需要将每三个条目中的每一个都当作广告来处理之外,我们还需要考虑从零开始的索引:我们在 2、5和8 上做广告。我们关心的是找到 3 的倍数(其中模运算返回零),这样我们就可以在每个位置上加上 1。这也消除了检查是否
position == 0
的需要(这种特殊的边缘情况表明你的逻辑不一致--别担心,我在写这篇文章的时候才意识到!)fun isCard(position: Int) = (position + 1) % 3 != 0
注意,我们在这里使用3是因为我们处理的是列表 * 中的 * 位置,该位置每隔 2 个位置就填充了一个广告。
cards
中的每 2 个项目就变成了适配器内容中的 2+1 个项目。实际上,我们应该使用一个常量
val ITEMS_PER_AD = 2
,并从它派生出另一个值val AD_FREQUENCY = ITEMS_PER_AD + 1
。避免了难以阅读和使用,并且容易混淆的 * 幻数 *。这更清晰(也许有更好的名称!),您可以更改ITEMS_PER_AD
来更改数量,其他所有内容都会沿着调整从
position
到card
的转换是最后一位。当position
* 不是 * 一个有效的卡时,你必须考虑,例如isCard
是false。在这种情况下,最容易在这里返回 null。看看翻译应该如何进行可能会有所帮助:
是的,这是一个逻辑难题,这个过程的模式是什么?
偏移发生在每 3 个项的倍数处,所以如果我们用
position
除以 3,然后减去它,消除这些偏移会怎样?很好,看起来不错!现在,如果不是卡片,我们需要返回 null,否则从数据集中获取合适的卡片:
这些都是正确调整列表大小、确定特定
position
是卡片还是广告以及从数据中获取适当卡片所需的部分。希望您可以了解如何将这些工作应用到Adapter
方法中,以确定您需要哪个itemViewType
,等等。实际上,你可以尝试在
onBindViewHolder
中输入getCardForPosition
,如果结果为 null,则显示一个广告(并将传递给你的ViewHolder
转换为 ad,因为这是你应该得到的,因为它们都使用相同的函数来确定什么是什么)。至于空格,当你所有东西都显示正确时,看看它是否能正常工作。它可能会自行解决,也可能是你的 ad 项目的布局问题。确保它们的宽度不是
match_parent
或任何东西。你可以随时使用Layout Inspector
和一个正在运行的应用程序来查看屏幕上的布局到底发生了什么,可能会给予你一些线索我想检查一下我是否遗漏了什么,所以我写了一个基本的实现,如果它有帮助的话:
非常简单,只需要在
ViewHolder
和TextView
中使用相同的布局。固定了布局的大小,没有空格弹出:希望能有所帮助!
ozxc1zmp2#
是的,这个很好用,我也有类似的东西可以帮助。
但这里的主要问题是,如果Admob未能加载广告呢?
如果存在此时无法从服务器加载广告的情况:
因此,每发布2个广告后,就会显示一个广告,在getItemViewType方法中,我们有模块函数**(位置%AD_FREQ.)**
因此,默认情况下,它将返回AD_TYPE和AD将不会加载,导致空的ItemAdHolder布局膨胀。此外,我们将跳过帖子项目,因为adslist的大小为0,我们正在更新帖子项目的索引,所以如何解决这个问题?我尝试在获取viewType之前检查adItems的大小,但没有帮助
我现在所尝试的是
x一个一个一个一个x一个一个二个x
在ITEM_TYPE案例的bindViewHolder()中