Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

wait until scrollToRowAtIndexPath is done in swift

I have a UITableView with more cells than fit on screen. When I get a notification from my data model I want to jump to a specific row and show a very basic animation.

My code is:

 func animateBackgroundColor(indexPath: NSIndexPath) {        
    dispatch_async(dispatch_get_main_queue()) {
        NSLog("table should be at the right position")
        if let cell = self.tableView.cellForRowAtIndexPath(indexPath) as? BasicCardCell {
            var actColor = cell.backgroundColor
            self.manager.vibrate()
            UIView.animateWithDuration(0.2, animations: { cell.backgroundColor = UIColor.redColor() }, completion: {
                _ in

                UIView.animateWithDuration(0.2, animations: { cell.backgroundColor = actColor }, completion: { _ in
                        self.readNotificationCount--
                        if self.readNotificationCount >= 0 {
                            var legicCard = self.legicCards[indexPath.section]
                            legicCard.wasRead = false
                            self.reloadTableViewData()
                        } else {
                            self.animateBackgroundColor(indexPath)
                        }
                })
            })
        }
    }
}    

func cardWasRead(notification: NSNotification) {
    readNotificationCount++
    NSLog("\(readNotificationCount)")

        if let userInfo = notification.userInfo as? [String : AnyObject], let index = userInfo["Index"] as? Int {

            dispatch_sync(dispatch_get_main_queue()){
                self.tableView.scrollToRowAtIndexPath(NSIndexPath(forRow: 0, inSection: index), atScrollPosition: .None, animated: true)

                self.tableView.layoutIfNeeded()
                NSLog("table should scroll to selected row")
            }
            self.animateBackgroundColor(NSIndexPath(forRow: 0, inSection: index))
        }
}

I hoped that the dispatch_sync part would delay the execution of my animateBackgroundColor method until the scrolling is done. Unfortunately that is not the case so that animateBackgroundColor gets called when the row is not visible yet -> cellForRowAtIndexPath returns nil and my animation won't happen. If no scrolling is needed the animation works without problem.

Can anyone tell my how to delay the execution of my animateBackgroundColor function until the scrolling is done?

Thank you very much and kind regards

like image 209
stu7000 Avatar asked Jun 04 '15 10:06

stu7000


1 Answers

Delaying animation does not seem to be a good solution for this since scrollToRowAtIndexPath animation duration is set based on distance from current list item to specified item. To solve this you need to execute animateBackgroudColor after scrollToRowAtIndexPath animation is completed by implementing scrollViewDidEndScrollingAnimation UITableViewDelegate method. The tricky part here is to get indexPath at which tableview did scroll. A possible workaround:

var indexPath:NSIndexpath?

func cardWasRead(notification: NSNotification) {
readNotificationCount++
NSLog("\(readNotificationCount)")

    if let userInfo = notification.userInfo as? [String : AnyObject], let index = userInfo["Index"] as? Int{

        dispatch_sync(dispatch_get_main_queue()){

            self.indexPath = NSIndexPath(forRow: 0, inSection: index)
            self.tableView.scrollToRowAtIndexPath(self.indexPath, atScrollPosition: .None, animated: true)

            self.tableView.layoutIfNeeded()

            NSLog("table should scroll to selected row")
        }

    }

}

func scrollViewDidEndScrollingAnimation(scrollView: UIScrollView) {
    self.animateBackgroundColor(self.indexPath)
    indexPath = nil
}
like image 158
Zell B. Avatar answered Oct 15 '22 02:10

Zell B.