Search code examples
iosswiftuikituiviewanimationtransition

How to do interactive transition + ending animation?


Normally, we can do an interactive transitioning with animateTransition of UIViewControllerAnimatedTransitioning and updating progress via UIPercentDrivenInteractiveTransition.

Question: How to have the interactive transitioning at first, then as we pass a certain threshold, perform a different ending animation?

What I want to achieve here is something like dismissing App store's Today card (https://gph.is/2qgcGHd). We can interactively shrink the card by panning a left edge of the screen. Then when it reaches the point, the card animates back to home page without any interactivity. It seems like a combination of interactive + animate transition to me.


What I've tried: I tried doing this in UIView.animateWithKeyFrames by dividing into two parts of animation with 0.5 relative times for each. Then as the progress reach 0.5, I call finish() (of UIPercentDrivenInteractiveTransition) to have the second animation performing. It has some glitches there and it's like a hack. Want to know if there's a better way to do this.


Solution

  • In the end, I use UIView.animateKeyFramesand dividing the interactive transition into two-part animation (as explained in the question):

    let progressUntilDismissing = 0.4
    UIView.animateKeyframes(withDuration: 0.5, delay: 0, options: [], animations: {
    
                    UIView.addKeyframe(withRelativeStartTime: 0.0,
                                       relativeDuration: progressUntilDismissing,
                                       animations: {
                            // interactive dismissing animation...
                    })
    
                    UIView.addKeyframe(withRelativeStartTime: progressUntilDismissing,
                                       relativeDuration: (1 - progressUntilDismissing),
                                       animations: {
                            // closing dismissing animation...
                    })
                }) { (finished) in
                 //...
    }
    

    Then in the pan gesture recognizer, I calculate the pan progress and determine if it passes progressUntilDismissing or not.

    If yes, call finish() on UIPercentDrivenInteractiveTransition subclass, it will animate the closing dismissing animation automatically.

    In case anyone is curious, this is what I'm playing with: AppStoreTodayInteractiveTransition