How to update each custom tableview cell data at the same time?

后端 未结 4 1241
长发绾君心
长发绾君心 2020-12-14 10:09

I am using Xcode 8.2.1 with Swift 3. I have one custom UITableViewCell containing a UITextView. When I type into the textView, the custom cell automatically gro

相关标签:
4条回答
  • 2020-12-14 10:45

    Once you update the data set with the new data. Reload the particular cells with the updated data set.

    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)
                           }
                      }
                }
            }
        }
    

    NOTE: If the modified data set cells are visible then only we have to reload the particular cells.

    0 讨论(0)
  • 2020-12-14 10:46

    Firstly, from storyboard or in your tableView Cell class set the textviews NumberOfLines = 0 .

    In the height for row delegate have

    override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return UITableViewAutomaticDimension
    }
    

    In your viewdidLoad add these lines:

    tableView.rowHeight = UITableViewAutomaticDimension
    tableView.estimatedRowHeight = 140
    

    In the 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)
    }
    

    By having the lines set to 0 and auto dimension height the cells automatically resize. Please also verify that you set your custom cells delegate to self in yourcellForRowmethod.

    0 讨论(0)
  • 2020-12-14 10:51

    I think the issue with automatic data entering is the fact that reloading of cells results in resignFirstResponder() call.

    This seems quite logical as on data reloading you actually give up some cells and ask the table view for new ones through cellForRowAt:. The old ones might not be the same so they resignFirstResponder().

    One way to update the text of a cell is to directly alter the cell contents. You can do this for text view contents. Unfortunately for cell height there is no way to directly alter the cell without triggering heightForRowAt:.

    UPDATE2: There IS a solution for iOS 8+ combining direct cell manipulation and AutomaticDimension on the table view.
    Working flawlessly for UITextView. Check updates below. This is how the final result looks like:

    UPDATE1: Code example for direct cell manipulation added

    Use simple model to hold table view data:

    // 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)]
    

    And delegate like this:

    // Delegate to update visible cells in the table view when text field value change.
    protocol TextChangeDelegate {
        func textChangedAtCell(_ cell: CustomCell, text: String?)
    }
    

    Then init your custom cell:

    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
    }
    

    In the Custom 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
        }
    }
    

    This is how to implement the TextChangeDelegate in the view controller with direct cell access, i.e. without reloading data:

    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.
        }
    }
    

    You now have simultaneous text update on all cells with same CellType. This example use UITextField (check UPDATE2 for UITextView).

    UPDATE2 goes here. Cell with UITextView with simultaneous text AND height adjustment.

    Use the model and controller from previous example (minor changes as you will use new cell). Utilize UITableViewCell and put UITextView inside. In AutoLayout set constraints to text view:

    Remember to disable scrolling and bounces to the text view (otherwise you will not have auto-height). Don't forget to link textView's delegate to the UITextViewCell subclass.

    Then in the cell, use

    func textViewDidChange(_ textView: UITextView) {
        self.textChangeDelegate?.textChangedAtCell(self, text: textView.text)
    }
    

    Then, super important, in the ViewController's viewDidLoad, add this two settings

    tableView.estimatedRowHeight = 50
    tableView.rowHeight = UITableViewAutomaticDimension
    

    and register the cell:

    tableView.register(UINib(nibName: "CustomTextViewCell", bundle: nil),
                       forCellReuseIdentifier: "customTextViewCell")
    

    Finally, add this code to TextChangeDelegate implementation from UPDATE1 to do the actual height update trick:

    func textChangedAtCell(_ cell: UITableViewCell, text: String?) {
    
        <code from UPDATE 1 goes here>
    
        tableView.beginUpdates()
        tableView.endUpdates()
    }
    

    Enjoy!

    0 讨论(0)
  • 2020-12-14 10:59

    every time you need update cell use this code:

    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()
    
     }
    
    0 讨论(0)
提交回复
热议问题