Home > Net >  CAEmitterLayer animation does not appear after drag and drop reordering of tableview cells
CAEmitterLayer animation does not appear after drag and drop reordering of tableview cells

Time:09-17

First time posting. Relatively new to Swift and iOS development. Getting the hang of it, but always trying new things and could use some help debugging the following issue. Thanks in advance!

Issue: I have a confetti animation that runs in a custom UIView that I add as a subview on button tap. I also have a tableview whose cells I would like to be re-orderable by drag and drop. To do this, I have implemented various UITableViewDragDelegate and UITableViewDropDelegate methods.

Individually, both of these features are working as expected.

However, one unforeseen side-effect I have encountered is that after a tableview cell is re-ordered, the confetti animation stops appearing until the app is closed and reloaded. This is true whether or not the confetti animation view is added on the same or different view controller.

Some observations:

  1. The confetti animation view is being added in the appropriate place in the view hierarchy and appears in the view hierarchy debugger.
  2. The confetti animation is being run on the main thread. I have checked that Thread.isMainThread returns True when it is being called.
  3. When itemsForBeginning runs, the animation still works as expected. By the time dropSessionDidUpdate runs, the animation stops appearing.

UPDATE:

  • Before deleting their comment, someone suggested creating a sample project to better illustrate the issue I'm running into, so here is a skeleton version of an app where you can reproduce the bug I'm trying to find a solution for. Sample App Github Repo

Here are the relevant drag & drop delegate methods I am using:

    func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
        let item = self.journals[sourceIndexPath.row]
        self.journals.remove(at: sourceIndexPath.row)
        self.journals.insert(item, at: destinationIndexPath.row)
    }
    
    func tableView(_ tableView: UITableView, itemsForBeginning session: UIDragSession, at indexPath: IndexPath) -> [UIDragItem] {
        return [UIDragItem(itemProvider: NSItemProvider())]
    }
    
    func tableView(_ tableView: UITableView, dropSessionDidUpdate session: UIDropSession, withDestinationIndexPath destinationIndexPath: IndexPath?) -> UITableViewDropProposal {     
        if session.localDragSession != nil { // Drag originated from the same app
            return UITableViewDropProposal(operation: .move, intent: .insertAtDestinationIndexPath)
        }
        return UITableViewDropProposal(operation: .cancel, intent: .unspecified)
    }
    
    func tableView(_ tableView: UITableView, performDropWith coordinator: UITableViewDropCoordinator) {
        //this method is not being called, but is required to conform to the UITableViewDropDelegate protocol.
    }

My confetti animation is being called as follows:

    let confettiView = ConfettiView()
    view.insertSubview(confettiView, belowSubview: reportsTable)
    confettiView.emit()

The emit() function configures CAEmitterCell, CAEmitterLayer and some other logic related to the animation. I'm not including that code for now since it works as long as the cells aren't reordered, but happy to do so if anyone thinks the problem might lie in how the animation is being generated.

I appreciate any ideas for solutions or things to investigate. Thanks again!

CodePudding user response:

The weird part is that I can follow your steps with your sample app, and reproduce the bug, but if I set a breakpoint on line 98 of ConfettiView.swift

addBirthrateAnimation(to: confettiLayer)

the program stops at the breakpoint, and when I continue it, the bug vanishes: the confetti behaves normally. So, If I replace that line with:

    DispatchQueue.main.asyncAfter(deadline: .now()   0.14) {
      addBirthrateAnimation(to: confettiLayer)
    }

the problem vanishes.

  • Related