Search code examples
iosswiftuitableviewcore-animationuianimation

How can i know when default functions animations finish?


In my application, i listed delivered notifications as sorted by date in tableView. If user tap to notifications from device notification screen, app highlights row. But before user presses notification on device main screen, if users scroll towards the end of the tableView, when user presses notification, app scrolls the tableView to the row with as an animated and also highlights the row.

But if users scrolled contentView to end of the tableView, highlight is not working. I think scroll to row animation function and highlight animation function working at same time.

How can i catch when tableView.scrollToRow(at: indexPath, at: .bottom, animated: true) animation finished. If i know when scrollToRow animation finish, i can run highlight row code after.

Thanks.

 DispatchQueue.main.async {
      self.tableView.scrollToRow(at: indexPath, at: .bottom, animated: true)
      
      if let cell = self.tableView.cellForRow(at: indexPath) as? NewsItemCell {
        
        let highlightView = UIView.init(frame: cell.contentView.frame)
        highlightView.backgroundColor = .white
        highlightView.alpha = 0.0
        cell.contentView.addSubview(highlightView)
        print(indexPath)
        
        UIView.animate(withDuration: 1.0, delay: 0, options: .curveEaseIn) {
          highlightView.alpha = 1.0
          
        } completion: { Bool in
          UIView.animate(withDuration: 1.5, delay: 0, options: .curveEaseOut) {
            highlightView.alpha = 0.0
          } completion: { Bool in
            highlightView.removeFromSuperview()
          }
        }
      }
    }

Solution

  • A UITableView is a subclass of UIScrollView.

    You should be able to implement the UIScrollViewDelegate method scrollViewDidEndScrollingAnimation(_:) in your table view delegate (usually the owning view controller) and then highlight the row in your implementation of that method. (You'll probably need to add logic and state variables to track the fact that you are in this situation.)

    Edit:

    Note that as mentioned in the answer from @trndjc linked by HangerRash, you should your follow-on animation code from a call to Dispatch.main.async(). (That will help avoid stutters in the animations.)

    From that answer:

    Second, despite the fact that the method is called on the main thread, if you're running a subsequent animation here (one after the scroll has finished), it will still hitch (this may or may not be a bug in UIKit). Therefore, simply dispatch any follow-up animations back onto the main queue which just ensures that the animations will begin after the end of the current main task (which appears to include the scroll-to-row animation). Doing this will give you the appearance of a true completion.

    func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) {
        DispatchQueue.main.async {
            // execute subsequent animation here
        }
    }