【问题标题】:UITableView resetting UITableViewCell after reloadingUITableView 重新加载后重置 UITableViewCell
【发布时间】:2018-10-10 14:20:48
【问题描述】:

首先我是如何使用 UIPicker 创建可扩展单元格的。以防万一这与问题有关。

它是由这段代码在 UITableView 中创建的

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    var identifyer = ""
    switch(indexPath.row){
  //other cells
    case 1:
        //Kategoria
        identifyer = "category"
        categoryCell = tableView.dequeueReusableCellWithIdentifier(identifyer) as? CategoryTableViewCell
        categoryCell.pickerView.delegate = self
        categoryCell.pickerView.dataSource = self
        return categoryCell
  //other cells
}

那我要识别它是否被触摸

override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    if (indexPath.row == 1){
        isCategoryCellSelected = true
        tableView.reloadRowsAtIndexPaths([categoryIndexPath()], withRowAnimation: UITableViewRowAnimation.Automatic)
    }
}

这就是我替换UILabel中文本的方式

func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
    categoryCell.categoryNameLabel.text = categories[row]
}

最后,当 tableView 刷新单元格时

override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    switch(indexPath.row){
    case 1:
        if (isCategoryCellSelected){
            return CategoryTableViewCell.expandedHeight
        } else {
            return CategoryTableViewCell.defaultHeight
        }
     //other heights
    }
}

默认单元格外观

展开的单元格外观

问题

因此,当我在选择器中选择项目时,上面的标签应该将其更改为文本,并且正在发生这种情况。但是,当此单元格缩小到默认高度时,替换效果就消失了。我必须向下和向上滚动才能看到它,然后我才能看到标签中更改的文本。

我假设 UITableView 缓存了这个单元格,当单元格重新加载时,它会采用这个缓存的版本。我只是猜测。是我的想法吗?我怎样才能改变这个不需要的动作?

解决方案

正如@the_critic 指出的那样,我在 vars 中保存单元格的方法是完全错误的。在同一时间,每次我选择行时重新创建 categoryCell 并不是正确的方法。我最终采用了他创建单元格的方式,但采用了我为单元格设置值的方式。

所以它看起来像这样:

创建单元格

categoryIdentifier 是private let String

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    var cell: UITableViewCell
    switch(indexPath.row){
// other cells
   case 1:
        //Kategoria
        print("recreate, selected category \(selectedCategory)")
        let categoryCell = tableView.dequeueReusableCellWithIdentifier(categoryIdentifier) as! CategoryTableViewCell
        categoryCell.pickerView.delegate = self
        categoryCell.pickerView.dataSource = self
        updateSelectedCategoryIfNeeded(categoryCell)
        cell = categoryCell

// other cells

    return cell;
}

private func updateSelectedCategoryIfNeeded(cell:CategoryTableViewCell) {
    if let selectedCategory = self.selectedCategory{
        // A category has been selected!
        cell.categoryNameLabel.text = selectedCategory
        updatePicekerRowPosition(cell)
    }else{
        // no category selected!
        cell.categoryNameLabel.text = "Wybierz kategorie..."
    }
}

private func updatePicekerRowPosition(cell:CategoryTableViewCell) {
    if let index = categories.indexOf(selectedCategory!){
        cell.pickerView.selectRow(Int(index.value), inComponent: 0, animated: false)
    }
}    

识别行选择

categoryIndexPath 是private let NSIndexPath

func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
    selectedCategory = categories[row]
    if let categoryCell = tableView.cellForRowAtIndexPath(categoryIndexPath) as? CategoryTableViewCell {
        categoryCell.categoryNameLabel.text = selectedCategory
    }
}

【问题讨论】:

  • 因此,您希望从选择器中选择“Wybierz kategorie”而不是“Wybierz kategorie”?顺便说一句,更改标签的代码在哪里?我猜它在选择器委托方法中,你也可以发布吗?
  • @the_critic 是的,我已经用pickerView(pickerView:didSelectRow:inComponent:) 完成了它,但是收缩后效果消失了,并且当此单元格展开时显示正确的视图。这就像两个分离的视图,它们在UITableView 重建后同步。也许视频可以更好地解释它。 vid.me/yLSQ 。我还用UIPicker 委托方法更新了我的问题。 :)

标签: ios swift uitableview


【解决方案1】:

从您的代码中可以看出,您对表格视图有很多误解。

我会尽量礼貌地说,但我不能。 您在代码中引用 categoryCell 的方式完全错误! 如果您将 UITableviewCells 出列,则它们不是静态引用!

第一步:删除categoryCell 变量!!!

表格视图的工作方式如下:

cellForRowAtIndexPath 方法从情节提要或您的笔尖中取出一个单元格,然后一遍又一遍地重用该单元格!因此,一开始,您可能会按照自己的方式进行操作(创建对categoryCell 的引用),但是一旦您的单元格超出屏幕大小,情况就会发生变化,因为变量将引用不同的单元格!

阅读推荐:Creating and Configuring a Table View

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

    var cell : UITableViewCell?
    switch(indexPath.row){
  //other cells
    case 1:
        //Kategoria
        let identifier = "category"
        // tableview checks if there is a cached cell 
        // for the identifier (reuse), 
        // if there is, it will take that one!
        cell = tableView.dequeueReusableCellWithIdentifier(identifier) as! CategoryTableViewCell
        cell.pickerView.delegate = self
        cell.pickerView.dataSource = self
        if let selectedCategory = self.selectedCategory{
            // A category has been selected!
            cell.categoryNameLabel.text = selectedCategory
        }else{
            // no category selected!
            cell.categoryNameLabel.text = "Wybierz kategorie..."
        }
        return cell
  //other cells
}

如您在上面看到的,我引入了一个名为selectedCategory 的新变量,它将反映当前选择的类别...

在你的控制器中这样设置:

var selectedCategory : String?

当您重新加载部分或行或整个表时,会再次调用给定行的所有UITableViewDataSource 方法!在某种程度上,表格视图总是试图反映模型的某些状态。

您应该始终通过重新加载行/部分或整个表来反映模型中的更改(取决于更改的内容)。

因此,当您选择类别时,您可以更改 模型 并重新加载您的行!

func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {

    // update the model!
    selectedCategory = categories[row]

    // the table view now needs to know that the model changed!
    // this will trigger the dataSource method cellForRowAtIndexPath
    // and because it selectedCategory is now set, it will update 
    // your string accordingly!
    tableView.reloadRowsAtIndexPaths([/*<IndexPath of your categoryLabelCell>*/], withRowAnimation: UITableViewRowAnimation.Automatic)

}

呸!希望对您有所帮助...

【讨论】:

  • 谢谢,我会试试这个。我认为使用变量中的单元格的方法是更好的解决方案,因为我不必从 tableView 中获取相同的单元格。我还认为如果 tableView 缓存它,那么它会以某种方式工作。
  • 我强烈建议您阅读我发布的链接以及相关链接。它们可以帮助您了解真正发生的事情......不要犯错误,并且会任性地去做。它会让你成为一个更好的程序员,你的代码更易于维护,你的同事(或未来的你)会感谢你。但是,如果您需要我的帮助,我会在这里回答您的更多问题!
  • 好的,我按照你说的做了,但是你的解决方案有一个不需要的问题。最好显示它vid.me/KNha 我最终得到了我要放入已编辑部分的代码。感谢您的建议,这真的很有帮助。你觉得我的解决方案怎么样?
  • @Dudi 你用过代码吗?您的 pickerView 是否与标签在同一个单元格中?如果没有,您应该只重新加载更改的类别标签的单元格。这有意义吗?
  • 是的,我使用代码。是的,pickerView 和 label 在同一个视图中。
猜你喜欢
  • 1970-01-01
  • 2013-04-07
  • 1970-01-01
  • 2011-03-29
  • 1970-01-01
  • 1970-01-01
  • 2011-08-26
  • 1970-01-01
相关资源
最近更新 更多