【问题标题】:Swift UITableView Show Different Cell Every 10th CellSwift UITableView 每 10 个单元格显示不同的单元格
【发布时间】:2017-11-28 19:17:54
【问题描述】:

我尝试使用两个数组在每 10 个单元格后显示一个不同的单元格:“ads”和“requests” 我希望我的 TableView 看起来像这样:

"Request"
"Request"
"Request"
"Request"
"Request"
"Request"
"Request"
"Request"
"Request"
"Request"
"Ad"
"Request"
"Request"
...

我知道如何制作广告,但不知道如何使用两个数组对这样的单元格进行排序。一点也不 :/ 有什么建议可以实现吗?提前致谢!

编辑:

func loadAds()
    {
        Api.adApi.observeAds
        {
            (ad) in
            self.list = self.requests
            for i in stride(from: self.adInterval, to: self.requests.count, by: self.adInterval).reversed()
            {
                // not getting executed
                print("test1")
                self.list.insert(ad, at: i)
            }
            // getting executed
            print("test2")
        }
    }

【问题讨论】:

    标签: arrays swift tableview cell


    【解决方案1】:

    cellForRowAt 中只需检查if indexPath.row % 10 == 0。如果是这样,那么您就是 10 的倍数。那么您需要做的就是实例化一个差异单元格。您还需要跟踪请求数据数组和广告数据数组的索引。你可以这样做。

    class MyViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
        var requestIndex = 0
        var adIndex = 0
    
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            if indexPath.row % 10 != 0 || indexPath.row == 0 {
                requestIndex += 1
                let cell = tableView.dequeueReusableCell(withIdentifier: "RequestCell", for: indexPath) as! RequestCell
                // configure cell with requestIndex
                // cell.imageView.image = requestDataArray[requestIndex].image
                return cell
            }
            else {
                let cell = tableView.dequeueReusableCell(withIdentifier: "AdCell", for: indexPath) as! AdCell
                adIndex += 1
                // configure cell with adIndex
                // cell.imageView.image = adDataArray[adIndex].image
                return cell
        }
    }
    

    您还可以使用一些基本数学来跟踪索引

    if indexPath.row % 10 != 0 {
        let requestIndex = indexPath.row - (indexPath.row / 10) // current indexPath - the number of adds already displayed
    }
    else {
        let adIndex = (indexPath.row / 10) + 1 // number of previously displayed ads plus one
    }
    

    【讨论】:

      【解决方案2】:

      有两种基本方法:

      1. 一个(由其他人描述)是拥有两个数组并让UITableViewDataSource 方法根据indexPath.row % 10 确定要出列的单元格。

        恕我直言,这里的问题是您的数据源方法中的逻辑很丑陋,将indexPath.row 映射到响应数组或广告数组中的适当行。

        因此,我建议使用实用函数 dataRowadRow 对相关数组中的索引进行逆向工程(如果 IndexPath 不相关,则返回 nil):

        extension ViewController: UITableViewDataSource {
        
            private func dataRow(for indexPath: IndexPath) -> Int? {
                let (quotient, remainder) = (indexPath.row + 1).quotientAndRemainder(dividingBy: adInterval)
                if remainder == 0 { return nil }
                return quotient * (adInterval - 1) + remainder - 1
            }
        
            private func adRow(for indexPath: IndexPath) -> Int? {
                let (quotient, remainder) = (indexPath.row + 1).quotientAndRemainder(dividingBy: adInterval)
                if remainder != 0 { return nil }
                return quotient - 1
            }
        
            func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
                return objects.count + ads.count
            }
        
            func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
                if let row = dataRow(for: indexPath) {
                    let cell = tableView.dequeueReusableCell(withIdentifier: "ItemCell", for: indexPath)
                    let object = objects[row]
                    // configure cell using model data, `object`
                    return cell
                } else if let row = adRow(for: indexPath) {
                    let cell = tableView.dequeueReusableCell(withIdentifier: "AdCell", for: indexPath)
                    let ad = ads[row]
                    // configure cell using ad data, `ad`
                    return cell
                }
        
                fatalError("Did not find data or ad for cell: Should never get here")
            }
        
        }
        

        顺便说一句,请注意我不只是在做indexPath.row % 10(因为我不希望首先显示的是广告)。所以我实际上是在做(indexPath.row + 1) % 10

      2. 另一种方法是使用单一视图模型结构来代表模型对象和广告的综合列表。例如,假设我有用于列表中项目和广告的模型对象:

        protocol Listable { }
        
        /// An Item is a model object for "real" objects to be shown in table 
        
        struct Item: Listable {
            let string: String
            let imageURL: URL
        }
        
        /// An Ad is a model object for advertisement to be inserted into table
        
        struct Ad: Listable {
            let string: String
        }
        

        然后,根据我的项目列表,我可以插入我的广告,构建项目和广告的综合列表:

        var items: [Item]! = ...
        var list: [Listable]!
        
        override func viewDidLoad() {
            super.viewDidLoad()
        
            // build consolidated list of items and ads
        
            list = items
            for i in stride(from: adInterval, to: items.count, by: adInterval).reversed() {
                list.insert(Ad(...), at: i)
            }
        }
        

        然后UITableViewDataSource 方法不必做任何数学计算来确定特定列表是哪个数组,而只需查看它是哪种类型并采取相应措施:

        extension ViewController: UITableViewDataSource {
        
            func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
                return list.count
            }
        
            func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
                let listing = list[indexPath.row]
        
                if let item = listing as? Item {
                    let cell = tableView.dequeueReusableCell(withIdentifier: "ItemCell", for: indexPath)
                    // configure cell using `item`
                    return cell
                } else if let ad = listing as? Ad {
                    let cell = tableView.dequeueReusableCell(withIdentifier: "AdCell", for: indexPath)
                    // configure cell using `ad`
                    return cell
                }
        
                fatalError("Did not find data or ad for cell: Should never get here")
            }
        
        }
        

      【讨论】:

      • 谢谢,最后一个问题。我的单元格没有显示,我在我的问题中添加了新代码,如果您能看一下,我将不胜感激。
      • requests 数组是代码中的 items 数组,adinterval 是一个 int。那是错的吗?我知道我听起来有点愚蠢,但我对这些东西很陌生:D
      • 对,所以我要求您确认 (a) 您的数组中有多少项目(即self.requests.count); (b) 你的adInterval 是什么(我用了 10 个)。我插入广告的方式,只有在requests 中有 10 个或更多项目时才会这样做。我还想确认您的数组不是空的。我还想确认您对adInterval 使用了合理的值。这就是我问的原因。此外,由于您没有调用 reloadData(),因此一旦您的 API 调用完成,它就不会重新加载表,这就是为什么我建议您确保在 API 闭包中调用它。
      • 还要确保 API 闭包正在主队列上运行,如果没有,则使用 DispatchQueue.main.async { ... } 将该闭包中的所有内容分派到主队列。
      • 好的,它现在有点工作了,但是当我滚动到 TableView 的底部时应用程序崩溃(错误消息:索引超出范围)
      【解决方案3】:

      尝试对将重复的单个广告进行此操作,但这会花费您 array[index%10] 值将不会显示

      func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
          if indexPath.row % 10 == 0 {
      
          //return ads cell
          }
          else{
          //normal cell
          }
      
      
          }
      

      如果我们有多个广告,我们可以每隔 n 个值在模型数组中插入广告,并添加额外的属性,比如 containsAds,这样我们就可以像这样检查

        if modelArray[indexPath.row].cotainAds {
            //return ads cell
           }
      else {
       //return normal cell
      }
      

      所以整个操作就是通过按特定顺序插入广告来修改原始数组

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-03-26
        • 1970-01-01
        • 2016-03-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多