【问题标题】:Show two different custom cells in same uitableview - swift firebase在同一个 uitableview 中显示两个不同的自定义单元格 - swift firebase
【发布时间】:2016-09-19 11:12:17
【问题描述】:

我目前在同一个 uitableview 上显示两种不同类型的自定义单元格时遇到问题。

到目前为止,我所管理的是接收更新单元的“更新”,称为cell。我只是不知道如何让 numberOfRowsInSection 返回两个值,所以我的两个单元格都会显示。

让我通过我的代码来解释一下:

override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        return 1
    }

    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return updates.count
        return updatesTask.count // I CANNOT DO THIS - what can I do instead?
    }



    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell:updateTableViewCell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! updateTableViewCell
        let cellTask:tasksTableViewCell = tableView.dequeueReusableCellWithIdentifier("TaskCell", forIndexPath: indexPath) as! tasksTableViewCell


        let update = updates[indexPath.row]
        let updateTask = updatesTask[indexPath.row]


        // Example of the two different cells that need different data from firebase
        cell.nameLabel.text = update.addedByUser
        cellTask.nameLabel.text = updateTask.addedByUser

您可能会看到,let updateTask 正在尝试获取indexPath.row,但这是不可能的,因为我不能在numberOfRowsInSection 中有两个返回值,这是一个问题,因为该数字指的是数据存储在我的 firebase 数据库中的位置。如何修改它以使其正常工作?

希望你们明白我的意思,否则请告诉我,我会尽力解释得更好:-)

【问题讨论】:

  • 请添加 cellForRowAtIndexPath 方法的其余部分,因为这在这种情况下也很重要。
  • 请告诉我您希望以什么顺序显示两个不同的单元格?所有单元格后跟所有任务单元格?
  • @SamM 这就是我目前所有的cellForRowAtIndexPath,如果我让它工作,以后还会有更多,我想在 cellTask​​ 之前显示单元格 - 如果可能的话?
  • 检查我的答案,它将显示所有单元格,然后显示所有单元格任务。如果您需要它们像 cell/cellTask​​/cell/cellTask​​... 告诉我,我会更新答案。
  • 我宁愿拥有那个!那将是真棒! @萨姆

标签: ios swift uitableview firebase


【解决方案1】:

如果您想将它们分成两个部分,@Callam 的回答非常棒。

如果您希望所有人都在一个部分中,这就是解决方案。

首先,在numberOfRowsInSection 方法中,您需要返回这两个数组计数的总和,如下所示:return (updates.count + updatesTask.count)

那么你需要像这样配置cellForRowAtIndexPath方法:

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

    if indexPath.row < updates.count{
        // Updates
        let cell:updateTableViewCell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! updateTableViewCell
        let update = updates[indexPath.row]
        cell.nameLabel.text = update.addedByUser
        return cell
    } else {
        // UpdatesTask
        let cellTask:tasksTableViewCell = tableView.dequeueReusableCellWithIdentifier("TaskCell", forIndexPath: indexPath) as! tasksTableViewCell
        let updateTask = updatesTask[indexPath.row-updates.count]
        cellTask.nameLabel.text = updateTask.addedByUser
        return cellTask
    }

}

这将显示所有单元格,然后显示所有单元格任务。


如果updates 数组和updatesTask 数组有相同数量的项目,并且你想一个一个地显示它们,你可以使用这个:

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

    if indexPath.row % 2 == 0 {
        // Updates
        let cell:updateTableViewCell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! updateTableViewCell
        let update = updates[indexPath.row/2]
        cell.nameLabel.text = update.addedByUser
        return cell
    } else {
        // UpdatesTask
        let cellTask:tasksTableViewCell = tableView.dequeueReusableCellWithIdentifier("TaskCell", forIndexPath: indexPath) as! tasksTableViewCell
        let updateTask = updatesTask[indexPath.row/2]
        cellTask.nameLabel.text = updateTask.addedByUser
        return cellTask
    }

}

【讨论】:

  • 有什么方法可以混合细胞吗?随机显示它们,而不是先显示所有更新,然后再显示所有 updateTasks?
  • @D.Finna updates 数组和updatesTask 数组是否有相同数量的项目?
  • 哦!我误解了你所说的相同数量的项目是什么意思!不,您不能确定 updates 和 updatesTask 中的项目数是否相等
【解决方案2】:
    override func numberOfSectionsInTableView(tableView: UITableView) -> Int {

        return 2
    }

    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

        switch section {
        case 0:
            return updates.count
        case 1:
            return updatesTask.count
        default:
            return 0
        }
    }    

    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

        switch indexPath.section {
        case 0:
            let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! updateTableViewCell
            let update = updates[indexPath.row]

            cell.nameLabel.text = update.addedByUser

            return cell
        case 1:
            let cell = tableView.dequeueReusableCellWithIdentifier("TaskCell", forIndexPath: indexPath) as! tasksTableViewCell
            let updateTask = updatesTask[indexPath.row]

            cell.nameLabel.text = updateTask.addedByUser

            return cell
        default:
            return UITableViewCell()
        }
    }

【讨论】:

    【解决方案3】:

    对于每一行,您必须选择是显示一种类型的单元格还是显示另一种类型的单元格,但不能同时显示两者。您应该在 numberOfRowsInSection 中有一个标志,告诉您的方法您要加载 Cell 或 CellTask​​,然后返回正确的行数。

    【讨论】:

      【解决方案4】:

      您应该在您的numberOfRowsInSection 方法中返回total number of rows。这样您就可以返回两个数组计数的summation,例如,

       return updates.count + updatesTask.count
      

      现在在您的 cellForRowAtIndexPath 方法中,您可以区分您的细胞,例如,

          let cell:updateTableViewCell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! updateTableViewCell
          let cellTask:tasksTableViewCell = tableView.dequeueReusableCellWithIdentifier("TaskCell", forIndexPath: indexPath) as! tasksTableViewCell
      
      
      
          if indexPath.row % 2 == 1 {
      
              //your second cell - configure and return
              return cellTask
          }
          else
          {
      
          //your first cell - configured and return
              return cell
          }
      

      【讨论】:

        【解决方案5】:

        我不确定你想要实现什么。如果你想显示单元格的数量 updates[] 和 updatesTask[] 有元素,你可以这样做

        override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return (updates.count + updatesTask.count)
        }
        

        然后你可以像这样修改你的 cellForRowAtIndexPath 方法:

        override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
            let cell:updateTableViewCell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! updateTableViewCell
            let cellTask:tasksTableViewCell = tableView.dequeueReusableCellWithIdentifier("TaskCell", forIndexPath: indexPath) as! tasksTableViewCell
        
        if indexPath.row < updates.count{
         //update 
         let update = updates[indexPath.row]
         cell.nameLabel.text = update.addedByUser
        }else{
            let updateTask = updatesTask[indexPath.row]
            cellTask.nameLabel.text = updateTask.addedByUser 
        }
        
            return cell
        }
        

        使用 if 条件,您可以选择从哪个数组中获取数据。 但请注意将数组命名为与您在此处所做的另一个常量完全相同的名称

        let updateTask = updatesTask[indexPath.row]
        

        【讨论】:

        • 我会试试你的代码,因为我相信它真的会帮助我解决我的问题。但请告诉我,&gt; 不应该反过来吗?喜欢这个&lt;?如果不是,请告诉我原因,因为我相信反过来说才有意义:-)
        • 应用程序崩溃,因为它在展开可选值时意外发现 nil。错误在这里:if indexPath.row &gt; updates.count{ 并且 indexPath.row 和 updates.count 都在打印 0
        • 你刚刚发布了这个 sn-p。如果你想要一个完整的答案,你必须发布你的整个班级。您可能没有在课堂上初始化您要求的数组。
        • 奇怪的是,如果我在我的代码中完全摆脱了 cellTask​​,我可以用一个自定义单元格显示我的提要吗?这对我没有意义。
        • 也许你应该先阅读苹果的 UITableView 文档,以便更好地了解它是如何工作的developer.apple.com/reference/uikit/uitableview
        【解决方案6】:

        您可以创建一个简单的视图模型,它将包含多种项目类型:

        enum ViewModelItemType {
           case nameAndPicture
           case about
           case email
           case friend
           case attribute
        }
        
        protocol ViewModelItem {
           var type: ViewModelItemType { get }
           var rowCount: Int { get }
           var sectionTitle: String  { get }
        }
        

        然后为每个部分创建一个模型项类型。例如:

        class ViewModelNameAndPictureItem: ViewModelItem {
           var type: ProfileViewModelItemType {
              return .nameAndPicture
           }
        
           var sectionTitle: String {
              return “Main Info”
           }
        
           var rowCount: Int {
              return 1
           }
        
           var pictureUrl: String
           var userName: String
        
           init(pictureUrl: String, userName: String) {
              self.pictureUrl = pictureUrl
              self.userName = userName
           }
        }
        

        一旦你配置了所有的部分项目,你就可以将它们保存在 ViewModel 中:

        class ProfileViewModel {
           var items = [ViewModelItem]()
        }
        

        并添加到您的 TableViewController:

        let viewModel = ViewModel()
        

        在这种情况下,NumberOfSections、NumberOfRows 和 CellForRowAt 方法将简洁明了:

        override func numberOfSections(in tableView: UITableView) -> Int {
              return viewModel.items.count
        }
        
        override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
              return viewModel.items[section].rowCount
        }
        
        override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            let item = viewModel.items[indexPath.section]
            switch item.type {
                  // configure celll for each type
            }
        }
        

        配置章节标题也会很整洁:

        override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
           return viewModel.items[section].sectionTitle
        }
        

        请查看我最近关于此主题的教程,它将通过详细信息和示例回答您的问题:

        https://medium.com/ios-os-x-development/ios-how-to-build-a-table-view-with-multiple-cell-types-2df91a206429

        【讨论】:

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