Search code examples
iosswifttableviewmessage

Change properties of previous cells in tableView


I have a tableView, designed in storyboard, that mimics a chat UI. A cell consists of:

  • A TextView for the message text
  • A Profile Image of the sender

Right now, the profile image is displayed in every cell, next to the text bubble. This is fine, but if the same users send two or more messages directly after the other, the profile image should only appear on the last bubble and not on the previous one.

I tried calling cellForRowAtIndexPath to get the previous cell's properties and change the hidden property of the profile image, but this gave me two problems:

  1. I'm calling cellForRowAtIndexPath inside cellForRowAtIndexPath, because that's where I make the cell UI and decide wether the profile image has to be hidden or not. I don't think it's a good idea to call this Method inside itself.
  2. Sometimes (when scrolling up and down very fast) this does not work properly.

I also tried to store all the cells in an dictionary (indexPath.row: Cell), so I can access it faster later, but this gave me the same problem namely that it does not work when scrolling up and down really fast.

This is an illustration of how it should be: http://tinypic.com/view.php?pic=2qavj9w&s=8#.Vfcpi7yJfzI


Solution

  • You need to both look ahead inside of your cellForRowAtIndexPath method and, as Paulw11 recommended, call reloadRowsAtIndexPaths after inserting the cell:

    import UIKit
    
    struct MyMessage {
        let sender: String
        let text: String
    }
    
    class MyTableViewCell: UITableViewCell {
        var message: MyMessage?
        var showProfileImage: Bool = false
    }
    
    class MyTableViewController: UITableViewController {
    
        private var _messages: [MyMessage] = []
    
        override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return self._messages.count
        }
    
        override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
            let message = self._messages[indexPath.row]
            let cell = tableView.dequeueReusableCellWithIdentifier("Cell") as! MyTableViewCell
            cell.message = message
            if self._messages.count > indexPath.row + 1 {
                let nextMessage = self._messages[indexPath.row + 1]
                cell.showProfileImage = message.sender != nextMessage.sender
            } else {
                cell.showProfileImage = true
            }
            return cell
        }
    
        func addMessage(message: MyMessage) {
            let lastIndexPath = NSIndexPath(forRow: self._messages.count - 1, inSection: 0)
            let indexPath = NSIndexPath(forRow: self._messages.count, inSection: 0)
            self._messages.append(message)
            self.tableView.beginUpdates()
            self.tableView.insertRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.Bottom)
            self.tableView.reloadRowsAtIndexPaths([lastIndexPath], withRowAnimation: UITableViewRowAnimation.Fade)
            self.tableView.endUpdates()
        }
    }