0

I have a UITableView with plenty of different custom cells 1 of those has a Lottie animation view and when I press a button or receive certain network messages the animation is supposed to jump to a specific position/progress and then animate either forward or backward.

So far, so good, all of this is working properly until I scroll down and the UITableViewCell gets recycled which stops my animation and I lose track of the proper position/progress.

I've thought about maybe using a timer and trying to sync it with the animation progress or maybe instantiate a hidden LottieAnimationView and syncing it with the visible one. Has anyone dealt with this problem before?

It's a fairly long, variable-length animation (usually between 20s and 30s) of a Curtain/Door that needs to be synced across multiple devices, the server sends me a message to each client whenever the curtain changes direction, the message includes the direction (open, closed or stopped) and its position as a percentage 0% to 100% (closed to open).

The animation is connected to a real device, a curtain, it is the feedback of that device, that's what the network calls are for, so it does not loop. Depending on the room the might be 2 to 4 cells with animations, each cell and animation corresponding to a different curtain, and a dozen or more cells that have 0 animations and are totally unrelated. Each cell stores a unique ID, the last motion of the curtain, the last received position for the curtain between 0% and 100% and the duration and speed of the animation.

The contents are all read from an XML file when the page is loaded. Then I'm using TCP communication to change states of switches, buttons and sliders. Like this: https://i.stack.imgur.com/sBYiX.jpg

Any suggestions?

TylerH
  • 20,799
  • 66
  • 75
  • 101
Watermamal
  • 357
  • 3
  • 12

2 Answers2

3

First of all you should know which cell is your animation cell and you should not dequeue that cell. You will create that cell in your controller so animation cell will never be reinitialized from your UITableView.

    let animationCell = AnimationCell()

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
       if indexPath.row == 0 { //0 is the animation cell
         return animationCell
        } else { 
         // try to dequeue your regular cell
        }
    }
andesta.erfan
  • 972
  • 2
  • 12
  • 30
  • 1
    The problem here is to know which frame to play from. The animation is of a curtain. I receive a network msg every time it changes directions (open, close or stopped) but I lose track of the animation progress when my tableview recycles the cell after scrolling. – Watermamal Aug 31 '19 at 14:51
  • Thanks, but now I need a way to make it look like the animation kept going when it went out of screen. I've been trying out with timeIntervalSinceNow to calculate time it was out of view and add it to progression but I haven't gotten there yet. – Watermamal Aug 31 '19 at 15:56
  • @Watermamal I thought you want to play it from where it was left (disappeared). – andesta.erfan Aug 31 '19 at 15:58
  • No, I want it to continue until it gets the stop signal from network, even when it goes outn of view. – Watermamal Aug 31 '19 at 16:04
  • @Watermamal So why not simply do not dequeue the cell with animation. Create your AnimationCell in your controller and in `cellForRowAt` if the `indexPath` is the animation cell return animationCell and do not dequeue it. With this approach your cell never reinitialized. – andesta.erfan Aug 31 '19 at 16:09
  • This works. I had thought about it but wasn't completely sure it would work with Lottie, it seems to be flawless. Sorry it took me some time to try since my project has gotten fairly complex by now. – Watermamal Sep 01 '19 at 16:38
0

Another approach that will also work even if you have lots of cells to dequeue and reuse:

Keep a static/global dictionary or cache somewhere, then store animationView.realtimeAnimationProgress there whenever tableView:didEndDisplaying: is called.

Then in tableView:willDisplay: you can assign that value back to animationView.currentProgress and then call play(toProgress:) with whatever original end state you were originally playing to.

This way the animation becomes resumable even in new cells. If you have a complex usecase, just store other information like the original desired end state and looping behavior. You might also need to store the current actual time, to adjust progress by however much real-world time has elapsed since the animation was frozen if the animation has scrolled off screen and you want it to come back as if time has passed instead of being frozen in time.

bcherry
  • 7,150
  • 2
  • 28
  • 37