Apple TV Focus Animation Coordinator Bug

If you know how to fix this, please ping me on Twitter.

Since tvOS 9.2, the addCoordinatedAnimations(-:completion:) method of UIFocusAnimationCoordinator has exhibited a strange behavior. Assume you have a collection view whose cells use either affine or 3D scale transforms to scale-up their contents when focused:

override func didUpdateFocusInContext(context: UIFocusUpdateContext, withAnimationCoordinator coordinator: UIFocusAnimationCoordinator) {
        coordinator.addCoordinatedAnimations({ 
            if self.focused {
                self.focusEffectsContainer.transform = CGAffineTransformMakeScale(1.158, 1.158)
            } else {
                self.focusEffectsContainer.transform = CGAffineTransformIdentity
            }
            }, completion: nil)
    }

If you scroll through the collection view very quickly, cells that acquire and then immediately lose focus before being scrolled into the visible bounds will appear to be scaled-down for a few moments before returning to their identity transform states.

Check out a video of the bug here. You can also download the sample project here

My best guess is that UIFocusAnimationCoordinator’s addCoordinatedAnimations method is using some unclamped animation parameters, which causes the return to an identity transform to over-downscale (like a bouncy animation). This, in conjunction with the (new since 9.2) delay applied to coordinated animations for offscreen views, might be causing the shrunken appearance of the cells awaiting the rest of their unfocusing animations.

I can “resolve” the issue by making nested UIView animation block calls from inside the addCoordinatedAnimations animation block argument, passing animation options that override the inherited curve and duration. But this results in sloppy looking animations all the time, even though it resolves the fast-scrolling transform edge case. I’d prefer to find a workaround that continues to use addCoordinatedAnimations the way it was intended.

|  14 Jun 2016