如何在集合视图中显示广告

Posted

技术标签:

【中文标题】如何在集合视图中显示广告【英文标题】:How to display ads within a collection view 【发布时间】:2017-03-28 06:37:48 【问题描述】:

我正在尝试在我的 collectionView 中随机添加一些横幅广告。

每个 collectionView 单元格都将是一个基本图像(这里是黑色方块以使事情更容易)从我从网络上获取的数组(假设它是一个非常长的数组并称之为“longDataArray”)动态填充。

我可以设法向我的 collectionView 添加一些横幅广告,但问题是它破坏了我的 longDataArray 的顺序。 例如,仅用于测试当我在 indexPath 6 处添加广告横幅时,广告横幅在 indexPath 6 处正确显示,并且我能够管理单元格的宽度更改,但是 我的 longDataArray 在 indexPath 6 处对应的图像显然永远不会出现。

我也可以将我的 longDataArray 分成两部分,然后使用这些部分:部分 0 = firstPartOfArray,部分 1 = 广告横幅,部分 2 = secondPartOfArray。但这需要花费大量精力来创建不同的数组和部分,只添加一个广告横幅,这显然不是我想要的。

所以我的问题是,如何在 collectionView 中添加横幅广告(只有一个部分),但保留 indexPath 逻辑?

我在谷歌上搜索了很多关于这个问题的信息,但很惊讶我无法为这个问题想出任何解决方案。

你们有什么想法吗?

谢谢!

【问题讨论】:

您使用的是表格视图还是集合视图?您的标题与内容不符。 对不起,我打错了,我的意思是collectionView,但无论您使用collectionView还是tableView,概念基本相同,我希望广告横幅出现在collectionView(或tableView)中随机(不仅是banner的位置,还有banner的数量)而不破坏indexPath的逻辑 我不会为广告创建另一个部分,而是将其插入到数组中的实际数据之间并添加某种标志来识别它(例如,theActualDataForACell[@"is_ad"] = @YES; 然后if ( [dataForCell[@"is_ad"] boolValue] ) /* this is an ad */ ,您可以在 UICollection​View​Delegate​Flow​Layout 协议的 collectionView:layout:sizeForItemAtIndexPath: 方法中定义特定单元格的大小...或者您可以创建另一个单元格原型并在适当时将广告出列。 这里也一样,你找到优雅的解决方案了吗? @armnotstrong 我认为 AlejandroIván 解决方案很简单,也是最好用的解决方案。您只需在随机位置添加一个特殊对象(由于显示的布局,可能需要至少是 3 的倍数,但这应该很容易。 【参考方案1】:

对于UICollectionView,您必须自定义两个UICollectionView

    Cell1 用于Imageview。 Cell2 用于横幅广告。

cellForItem

if (indexPath.item == 6)
    // dequeue your cell2 here
    return cell2

else
    // dequeue your cell1 here
    return cell1

实现UICollection​View​Delegate​Flow​Layout并像这样使用

func collectionView(_ collectionView: UICollectionView, 
                      layout collectionViewLayout: UICollectionViewLayout, 
               sizeForItemAt indexPath: IndexPath) -> CGSize

  if (indexPath.item == 6)
      return CGSizeMake(60,60)
  
  else
      return CGSizeMake([[UIScreen mainScreen] bounds].size.width, 60.0)
  


要在您的应用中展示广告,请AdMob

【讨论】:

感谢您的回复@agent_stack,但是,如果我这样构建它,问题是我将不得不拆分我的数据,这不是我想要的(我的数据将动态增长并且将很大) 如果您有任何想法,我正在寻找一种不会改变我的数据和 indexPath 逻辑的解决方案? @jellyfish6 您的用户界面实际上是如何显示的,您可以告诉我,以便我可以相应地提出建议。请描述您拥有的数据类型以及您在集合视图中显示的内容 再次感谢您的快速回复!在这个屏幕上,用户将能够看到他们朋友分享的所有照片。所以基本上我的 dataArray 将包含在一个结构数组中,我的 dataArray = [PhotoStruct] 并且每个 PhotoStruct 都由一个 photoImageURL、一个 photoAuthor 和一个 photoTime 组成,我将抓取并使用它们来填充 collectionView。 每个集合单元格将包含照片图像(完整单元格大小),底部的作者标签和顶部的时间标签。【参考方案2】:

您好,我在表格单元格中创建了一个具有相同要求的 collectionView,您可以查看我的代码。

//
//  ViewController.swift
//  DemoApp
//
//  Created by Mahesh Kumar on 09/01/18.
//  Copyright © 2018 Mahesh Kumar. All rights reserved.
import UIKit

class TableCell : UITableViewCell
    @IBOutlet weak var collVw: UICollectionView!
    @IBOutlet weak var categoryName: UILabel!


class ViewController: UIViewController, UICollectionViewDelegate,UICollectionViewDataSource , UICollectionViewDelegateFlowLayout , UITableViewDelegate,UITableViewDataSource 

    var categories_array = ["Home","Helth","New","Home1","Home2","Home3","Home4","Home5","Home6","Home7","Home8","Home9","Home11","Home12","Home13","Home14","Home15"]

    //Mark
    var sectionArray = NSMutableArray()


    @IBOutlet weak var tableVw: UITableView!
    override func viewDidLoad() 
        super.viewDidLoad()

        //Mark
        var sectionCount = 0
        var mainIndex = 0

        let section = categories_array.count % 4
        if(section == 0)
            sectionCount =  categories_array.count/4
        
        else
             sectionCount =  categories_array.count/4 + 1
        
        //Mark
        for _ in 0...sectionCount 
            let rowsData = NSMutableArray()
            var j = 0
            while  j<4
                if(mainIndex == categories_array.count)
                    break
                
                rowsData.add(categories_array[mainIndex])
                j = j + 1
                mainIndex = mainIndex + 1

            
          sectionArray.add(rowsData)


        

        tableVw.reloadData()

        // Do any additional setup after loading the view, typically from a nib.
    

    override func didReceiveMemoryWarning() 
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
        return 3
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
        let cell = tableVw.dequeueReusableCell(withIdentifier: "cell1", for: indexPath) as? TableCell

        if(indexPath.row == 1)
            cell?.categoryName.text = "Top Redeemed"
        
        else if(indexPath.row == 2)
            cell?.categoryName.text = "Categories"
        

        cell?.collVw.tag  = indexPath.row
        cell?.collVw.delegate = self
        cell?.collVw.dataSource = self
        cell?.collVw.reloadData()

        return cell!
    

    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat 

        return 400
    


    func numberOfSections(in collectionView: UICollectionView) -> Int 
        if(collectionView.tag == 0)
              return 1
        
        else if(collectionView.tag == 1)
            if(categories_array.count > 4)
            if(categories_array.count % 4 == 0)
                return categories_array.count/4
            
            else
                return (categories_array.count/4) + 1
            
            
            else
                return 1
            

        
        else
            return 10
        


    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell 
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath)
        cell.backgroundColor = UIColor.green
        if let lbl = cell.viewWithTag(1) as? UILabel
            lbl.text = "\(indexPath.row)"
        
        return cell

    
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize
    
        if(collectionView.tag == 0)
             return CGSize.init(width:  collectionView.frame.width - 10, height: collectionView.frame.height)
        
        else if(collectionView.tag == 1)
            return CGSize.init(width:  (collectionView.frame.width)/2 - 5.5, height: collectionView.frame.height/2 - 0.5)

        
       else 
            return CGSize.init(width:  collectionView.frame.width/3 - 4, height: collectionView.frame.height/2 - 0.5)
        

    


    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat 
        if(collectionView.tag == 0)
            return 10
        
        else
            return 1
        
    

   func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets
   
       return UIEdgeInsets(top: 0, left: 5, bottom: 0, right: 5)
   




    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int 
        if(collectionView.tag == 0)
           return 10
        
         else if(collectionView.tag == 1)
            return ((sectionArray[section] as? NSMutableArray)?.count)!
        
         else
             return 6
        

    

    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) 
        print("coll vw",indexPath.row)
        print(indexPath.section)

        //Mark
        if(collectionView.tag == 1)
            print(collectionView.tag)
            let array = sectionArray[indexPath.section] as? NSMutableArray
            print(array![indexPath.row])
        

    



【讨论】:

请添加此代码,它会创建一个三部分,一是广告横幅,二和三是类别,用户可以水平和垂直滚动。如果有效,请接受我的回答。【参考方案3】:

所以我的问题是,你将如何在你的 collectionView 中添加横幅广告(只有一个部分),但保留 indexPath 逻辑?

您只需调整索引路径以考虑广告。例如,假设您希望每 15 个单元格包含一个广告。让我们在这里使用基于 1 的算术来使数学更直观。单元格 1-14 将获得它们的常规内容,单元格 15 将有一个广告,单元格 16-29 将获得项目 15-28 的内容,单元格 30 将获得另一个广告,依此类推。因此,您的 -collectionView:cellForItemAtIndexPath: 方法需要确定索引路径是指广告单元格(在这种情况下,从 1 开始的项目编号可以被 15 整除)还是内容单元格(每隔一个单元格)。在后一种情况下,它还需要调整项目编号以获得正确的内容。

NSInteger item = indexPath.item + 1;   // switch to 1-based numbering
if (item % 15 == 0) 
    // we have an ad cell, so return a cell configured with an ad

else 
    item = item - (item / 15); // subtract the ad cells
    item -= 1;                 // switch back to 0-based indexes
    // return a cell configured with the data at index `item`

您还必须在其他处理单元格的方法中进行相应的计算,例如-collectionView:numberOfItemsInSection:。因此,编写一些可以进行调整的实用方法可能是一个好主意。

【讨论】:

嗨@Caleb,感谢您的详细回答!我没有想到这一点,但是,这很有意义!使用它,我可以跟踪我的原始 indexPath 并相应地获取数据。但是,在我在问题中提出的随机广告展示位置(并非总是每 15 个单元格)的情况下,您将如何使其工作?您将如何跟踪这种随机性?你能解释一下吗 如果您随机放置广告,则无法使用公式计算索引。我认为在这种情况下,我会保留一个广告位置列表,然后使用该列表来计算差异。例如,如果您有一个像 [13, 27, 43, 58, 71] 这样的广告位置列表,那么每次填充一个单元格时,您都需要查看该列表并确定该单元格之前有多少广告。如果您正在填充单元格 #30,则查看列表并看到有两个广告 另一种方法:在您的数据中插入广告占位符。只需将一种新的项目添加到您正在管理的项目列表中,并让您的代码在大多数情况下忽略这些项目。这样可以避免进行数学运算来调整项目索引,但可能会使代码的其他部分复杂化。【参考方案4】:

我们成功地为这个问题与 Ersin 开发了一个示例。

你可以在这里查看。

https://github.com/Cemoo/WaterFlowLayout

【讨论】:

以上是关于如何在集合视图中显示广告的主要内容,如果未能解决你的问题,请参考以下文章

如果集合视图嵌入到 ios 的表视图中,如何始终显示集合视图的第一项

可区分的集合视图如何在多个部分中显示相同的项目?

如何在集合视图中从数组显示项目到特定的 indexPath [关闭]

如何在 RecyclerView 之间添加 Facebook Audience Network 原生广告

如何在可扩展的表格视图单元中制作动态集合视图

Swift UI集合视图 - 如何在Cell中显示“segued”用户输入?