3

My tableView scrolling is jumping when I reload tableView with new data. Here is the code for cellForRowAtIndexPath:

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
     let section = indexPath.section
     let index = indexPath.row
     let info = data[sections[section]]![index] as ConversationMessage

     if info.from == .Me {
         var cell: ConversationDialogMeTableCell = tableView.dequeueReusableCellWithIdentifier("meCell", forIndexPath: indexPath) as! ConversationDialogMeTableCell
         cell.backgroundColor = UIColor.clearColor()
         cell.selectionStyle = .None
         cell.messageLabel.text = info.text
         return cell
     } else if info.from == .Other {
         var cell: ConversationDialogOtherTableCell = tableView.dequeueReusableCellWithIdentifier("otherCell", forIndexPath: indexPath) as! ConversationDialogOtherTableCell
         cell.backgroundColor = UIColor.clearColor()
         cell.selectionStyle = .None
         cell.personName.textColor = UIColor(hex: 0x6d6d6d)
         cell.messageContainerView.backgroundColor = UIColor(hex: 0x6d6d6d)
         cell.messageContainerView.layer.cornerRadius = 5
         cell.messageContainerView.clipsToBounds = true
         Alamofire.request(.GET, info.personImage).response {
             (request, response, data, error) in
             let image = UIImage(data: data!, scale: 1)!
             cell.personImage.image = image
             cell.personImage.contentMode = UIViewContentMode.ScaleAspectFill
             cell.personImage.layer.cornerRadius = cell.personImage.frame.height / 2
             cell.personImage.clipsToBounds = true
         }
         cell.personName.text = info.personName
         cell.personMessage.text = info.text
         return cell
    }
    return UITableViewCell()
}

For the first load scrolling is smooth, but if I will add new data in my tableView and call reloadData() the scrolling is jumping when new cells are shown.

Here is the code where I insert new data to my model:

func client(client: PubNub!, didReceiveMessage message: PNMessageResult!) {
    if message.data.subscribedChannel == self.channel {
        if let messageInfo: AnyObject = message.data.message {
            let date = (messageInfo["date"] as! String).getDateString()
            let messageText = messageInfo["message"] as! String
            let from: ConversationMessage.sendFromType = (messageInfo["userID"] as! String) == self.userID ? .Me : .Other
            let image = messageInfo["userPhoto"] as! String
            let name = messageInfo["userName"] as! String
            if data[date] != nil {
                data[date]!.append(ConversationMessage(text: messageText, from: from, personImage: image, personName: name, date: messageInfo["date"] as! String))
            } else {
                data[date] = [ConversationMessage(text: messageText, from: from, personImage: image, personName: name, date: messageInfo["date"] as! String)]
            }
            for section in self.sections {
                self.data[section]! = sorted(self.data[section]!) { Utils.compareDateTime($0.date, with: $1.date, order: .OrderedAscending) }
            }
            tableView.reloadData()
            tableViewScrollToBottom(false)
        }
    }
}

Maybe it happens because of function to scroll tableView to bottom:

func tableViewScrollToBottom(animated: Bool) {
    let delay = 0.1 * Double(NSEC_PER_SEC)
    let time = dispatch_time(DISPATCH_TIME_NOW, Int64(delay))

    dispatch_after(time, dispatch_get_main_queue(), {
       let numberOfSections = self.tableView.numberOfSections()
       let numberOfRows = self.tableView.numberOfRowsInSection(numberOfSections - 1)
       if numberOfRows > 0 {
           let indexPath = NSIndexPath(forRow: numberOfRows - 1, inSection: (numberOfSections - 1))
           self.tableView.scrollToRowAtIndexPath(indexPath, atScrollPosition: UITableViewScrollPosition.Bottom, animated: animated)
       }
    })
}

One more thing. Should I cache uploaded images? Maybe this is causing jumping scroll. Can someone help me to solve my issue?

maxshuty
  • 9,708
  • 13
  • 64
  • 77
mkz
  • 2,302
  • 2
  • 30
  • 43
  • What is your desired outcome? That the `tableView` loads more data up top but the user stays where they currently are? Or that when new data is reloaded the user is moved to the first cell to see the new data? – pbush25 Oct 22 '15 at 15:53
  • @pbush25 My data is coming from top to bottom, so when new data comes it is added to the end of my model array and I need to scroll to the bottom of the `tableView` after `reloadData()`. – mkz Oct 22 '15 at 18:04
  • Did you ever try caching the row heights? – Apophenia Overload Oct 31 '16 at 23:09
  • http://stackoverflow.com/a/40042923/3548469 Look at this once – Devang Tandel Dec 13 '16 at 07:17
  • There seems to be a **bug** for when you use `UITableViewAutomaticDimension `. See [this answer](https://stackoverflow.com/questions/8640409/how-to-keep-uitableview-contentoffset-after-calling-reloaddata/31324129#31324129) and other answers to the question. – mfaani Oct 10 '18 at 03:57

1 Answers1

1

Do not return UITableViewAutomaticDimension from

-(CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath;

There may be two possible solutions -

  • Either you should return max height for your cell.
  • OR you may cache the cell.bounds.size.height from tableView:willDisplayCell:forRowAtIndexPath: and return same value in estimatedHeightForRowAtIndexPath