Ios 如何同时更新每个自定义tableview单元格数据?

Ios 如何同时更新每个自定义tableview单元格数据?,ios,iphone,swift,uitableview,tableviewcell,Ios,Iphone,Swift,Uitableview,Tableviewcell,我正在使用Xcode 8.2.1和Swift 3。我有一个自定义UITableViewCell,其中包含UITextView。当我在文本视图中键入时,自定义单元格会自动增长。这部分工作正常。我还想在键入特定单元格时用相同的数据更新其他单元格。例如: 当我在第5个单元格中键入文本时,会自动在第11、15和18个单元格中输入相同的数据。这些细胞也必须自动生长。我已将数据添加到数组的特定索引中。但是它不会反映在表视图中。如何实现此功能 请检查我迄今为止实现的以下代码。此updateCellHeight

我正在使用Xcode 8.2.1和Swift 3。我有一个自定义UITableViewCell,其中包含UITextView。当我在
文本视图中键入时,自定义单元格会自动增长。这部分工作正常。我还想在键入特定单元格时用相同的数据更新其他单元格。例如:

当我在第5个单元格中键入文本时,会自动在第11、15和18个单元格中输入相同的数据。这些细胞也必须自动生长。我已将数据添加到数组的特定索引中。但是它不会反映在
表视图中。如何实现此功能

请检查我迄今为止实现的以下代码。此
updateCellHeight
方法是一个自定义委托方法。当用户在
textView
中键入时,将调用此方法

func updateCellHeight(indexPath: IndexPath, comment: String) {

    let currentCellLyricVal = self.traduzioneArray[indexPath.row]["rics"]
    tempIndexArray.removeAll()

    for (index,element) in traduzioneArray.enumerated() {

        let lyricVal = element["rics"]
        if currentCellLyricVal == lyricVal {
            tempIndexArray.append(index)
        }
    }
    for index in tempIndexArray {
        self.traduzioneArray[index]["ione"] = comment
        self.lyricsTableView.beginUpdates()
        self.lyricsTableView.endUpdates()
    }
}

func textViewDidChange(_ textView: UITextView) {
    self.delegate.updateCellHeight(indexPath: self.cellIndexPath, comment: textView.text)
}

首先,从storyboard或在tableView单元格类中设置textviewsNumberOfLines=0

在代表行的高度中有

override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    return UITableViewAutomaticDimension
}
在viewdidLoad中添加以下行:

tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 140
在tableViewController中

 func updateCellHeight(indexPath: IndexPath, comment: String) {

    let currentCellLyricVal = self.traduzioneArray[indexPath.row]["rics"]
    tempIndexArray.removeAll()

    for (index,element) in traduzioneArray.enumerated() {

        let lyricVal = element["rics"]
        if currentCellLyricVal == lyricVal {
            tempIndexArray.append(index)
        }
    }
    for index in tempIndexArray {
        self.traduzioneArray[index]["ione"] = comment
    }
      tableView.reloadRows(at: [IndexPath(row: 11, section: 1),IndexPath(row: 13, section: 1)], with: UITableViewRowAnimation.none)
}

通过将直线设置为0和“自动标注高度”,单元格将自动调整大小。还请验证您是否在
cellForRow
方法中将自定义单元格委托给self

使用新数据更新数据集后。使用更新的数据集重新加载特定单元格

func updateCellHeight(indexPath: IndexPath, comment: String) {
        DispatchQueue.main.async {
            let currentCellLyricVal = self.traduzioneArray[indexPath.row]["rics"]
            tempIndexArray.removeAll()

            for (index,element) in traduzioneArray.enumerated() {

                let lyricVal = element["rics"]
                //You have to skip the current cell. by checking index != indexPath.row
                if currentCellLyricVal == lyricVal, index != indexPath.row {
                    tempIndexArray.append(index)
                }
            }

            for index in tempIndexArray {
                self.traduzioneArray[index]["ione"] = comment

                let updatedIndexPath = IndexPath(row: index, section: indexPath.section)
                  if let visibleCellIndexPaths = tableView.indexPathsForVisibleRows  {
                       if visibleCellIndexPaths.contains(updatedIndexPath) {
                            tableView.reloadRows(at: [updatedIndexPath], with: .automatic)
                       }
                  }
            }
        }
    }

注意:如果修改后的数据集单元格可见,则只需重新加载特定单元格即可

我认为自动数据输入的问题在于,重新加载单元格会导致
辞职firstresponder()
调用

这似乎很合乎逻辑,因为在重新加载数据时,您实际上放弃了一些单元格,并通过
cellForRowAt:
向表视图请求新的单元格。旧的可能不一样,因此它们
辞职FirstResponder()

更新单元格文本的一种方法是直接更改单元格内容。可以对文本视图内容执行此操作。不幸的是,对于单元格高度,如果不触发
heightForRowAt:
,就无法直接更改单元格

更新2:iOS 8+提供了一种解决方案,它将直接单元格操作和表格视图上的自动标注结合起来。
为UITextView完美地工作。检查下面的更新。最终结果如下所示:

UPDATE1:添加了直接单元格操作的代码示例

使用简单模型保存表视图数据:

// Simple model, for the example only
class Model {
    // The value of the text field
    var value: String?
    // The type of the cell
    var type: CustomCell.CellType = .typeA

    init(value: String) {
        self.value = value
    }

    init(value: String, type: CustomCell.CellType) {
        self.value = value
        self.type = type
    }
}

// Init the model.
var tableData = [
    Model(value: "Cell Type A", type: .typeA),
    Model(value: "Cell Type B", type: .typeB),
    Model(value: "Cell Type B", type: .typeB),
    Model(value: "Cell Type A", type: .typeA),
    Model(value: "Cell Type B", type: .typeB)]
然后像这样委派:

// Delegate to update visible cells in the table view when text field value change.
protocol TextChangeDelegate {
    func textChangedAtCell(_ cell: CustomCell, text: String?)
}
然后初始化自定义单元格:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    // Will crash if identifier is not registered in IB
    let cell = tableView.dequeueReusableCell(withIdentifier: "customCell") as! CustomCell

    // For this to work you need to update the model on each text field text change
    cell.textValue.text = tableData[indexPath.row].value
    cell.index = indexPath.row
    cell.type = tableData[indexPath.row].type
    cell.textChangeDelegate = self

    return cell
}
在自定义单元格中:

class CustomCell: UITableViewCell {

    // The type of the cell. Cells with same type will be updated simultaneously.
    enum CellType {
        case typeA
        case typeB
    }

    // Very simple prototype cell with only one text field in it
    @IBOutlet weak var textValue: UITextField!

    // Default type
    var type = CellType.typeA
    // Index in the model. Not optional (or other special assumptions on initial value)
    // for simplicity of the example.
    var index = 0
    var textChangeDelegate: TextChangeDelegate?
}

extension CustomCell: UITextFieldDelegate {

    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {

        // Assume we will return true. Any logic could appear here.
        // If we need to return false, don't call the delegate method.
        let result = true

        if result {
            let nsString = textField.text as NSString?
            let newString = nsString?.replacingCharacters(in: range, with: string)
            print("New: \(newString ?? "(nil)")")

            textChangeDelegate?.textChangedAtCell(self, text: newString)
        }

        return result
    }
}
这是如何在视图控制器中通过直接单元格访问实现TextChangeDelegate,即不重新加载数据:

extension ViewController: TextChangeDelegate {

    func textChangedAtCell(_ cell: CustomCell, text: String?) {

        // Only visual update. Skip the cell we are currently editing.
        for visibleCell in tableView.visibleCells where visibleCell != cell {
            if let currentCell = visibleCell as? CustomCell,
                tableData[currentCell.index].type == cell.type {
                    currentCell.textValue.text = text
            }
        }

        // Update the model (including invisible cells too)
        for (index, data) in tableData.enumerated() where data.type == cell.type {
            tableData[index].value = text
        }

        // Avoid reloading here, as this will trigger resignFirstResponder and you will
        // have issues when jumping from text field to text field across cells.
    }
}
现在,所有具有相同单元格类型的单元格都可以同时进行文本更新。本例使用UITextField(检查UITextView的UPDATE2)

UPDATE2在这里。带有UITextView的单元格,可同时调整文本和高度。

使用上一个示例中的模型和控制器(在使用新单元时做一些小更改)。 利用UITableViewCell并将UITextView放入其中。在“自动布局”中,将约束设置为文本视图:

记住禁用滚动并将其反弹到文本视图中(否则将无法自动调整高度)。 不要忘记将textView的委托链接到UITextViewCell子类

然后在单元格中,使用

func textViewDidChange(_ textView: UITextView) {
    self.textChangeDelegate?.textChangedAtCell(self, text: textView.text)
}
然后,在ViewController的viewDidLoad中,添加这两个设置

tableView.estimatedRowHeight = 50
tableView.rowHeight = UITableViewAutomaticDimension
并注册该单元格:

tableView.register(UINib(nibName: "CustomTextViewCell", bundle: nil),
                   forCellReuseIdentifier: "customTextViewCell")
最后,将以下代码从UPDATE1添加到TextChangeDelegate实现中,以执行实际高度更新技巧:

func textChangedAtCell(_ cell: UITableViewCell, text: String?) {

    <code from UPDATE 1 goes here>

    tableView.beginUpdates()
    tableView.endUpdates()
}
func textChangedAtCell(cell:UITableViewCell,text:String?){
<更新1中的代码在此显示>
tableView.beginUpdate()
tableView.endUpdates()
}

享受吧

每次需要更新单元格时,请使用以下代码:

func updateCellHeight(indexPath: IndexPath, comment: String) {

  //update dataModel according to new text
  ...
  //then reload visible tableview rows
  //pay atttention to beginUpdates endUpdates methods.
  //This do the trick)

  tableView.beginUpdates()
  tableView.reloadRows(at: indexPathsForVisibleRows ?? [], with: .none)
  tableView.endUpdates()

 }

但我不能手动提到重新加载特定行,如13、11、15等。还有一件事是“重新加载行”会导致自动关闭键盘。但使用此代码,每次我键入每个字母时,键盘都会自动关闭。为每个字符更改重新加载单元格不是好的做法。一旦您完成编辑,我们就可以更新单元格。@JAK func textViewDiEndediting(textView:UITextView){self.delegate.updateCellHeight(indexath:self.cellIndexPath,comment:textView.text)}需要从textViewDiEndediting和textViewDidChange调用self.delegate.updateCellHeight吗?否。。仅textViewDidEndEditingUpdate:提供了有关如何使用直接单元格操作的代码示例。已使用iOS 8+的完整解决方案进行更新。现在您可以在不松开键盘的情况下自动更新文本和单元格高度。非常感谢..太好了。。太好了,谢谢你,杰克。我编辑了答案,以强调最终解决方案,并删除了一些旧文本。很高兴这个解决方案能帮助你!欢迎!这很有帮助。非常感谢。