Home

Awesome

iOS 11 App Store Transition

Just another attempt to simulate App Store's Card transition:

demo

Implementation details are available in slides under the MobileConf folder, in the last section ('5 Phases of Interaction').

My previous repo is here. The new one is a total rewrite. It has better effect/performance, better code organization, and has fixes for some issues found in the previous repo.

Overview

All is done with native APIs (UIViewControllerAnimatedTransitioning, etc.), no external libraries. This is NOT a library to install or ready to use, it's an experiementation/demo project to show how such App Store presentation might work.

Features (that you might not know exist)

Interesting code

TODOs/Defects

Here are some implementation details:

5 Phases of Interaction

1. Highlighting

2. Before Presenting

3. Presenting*

Wait, how to animate different AutoLayout constraints with different animation curves?

// Animate constraints on the same view with different animation curves
UIView.animate(withDuration: 0.6 * 0.8) {
  self.widthAnchor.constant = 200
  self.heightAnchor.constant = 320
  self.targetView.layoutIfNeeded()
}
UIView.animate(withDuration: 1, delay: 0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0, options: [], animations: {
  self.topAnchor.constant = -200
  self.targetView.layoutIfNeeded()
}) { (finished) in ... }

4. Interactively Dismissing

dragDownPan.require(toFail: leftEdgePan)
scrollView.panGestureRecognizer.require(toFail: leftEdgePan)
var draggingDownToDismiss = false // A flag to check mode

func scrollViewDidScroll(_ scrollView: UIScrollView) {
  if draggingDownToDismiss || (scrollView.isTracking && scrollView.contentOffset.y < 0) {
    draggingDownToDismiss = true
    scrollView.contentOffset = .zero // * This is important to make it stick at the top
  }
  scrollView.showsVerticalScrollIndicator = !draggingDownToDismiss
}
let shrinking = UIViewPropertyAnimator(duration: 0, curve: .linear, animations: {
  self.view.transform = .init(scaleX: 0.8, y: 0.8)
  self.view.layer.cornerRadius = 16
})
shrinking.pauseAnimation()
shrinking!.pauseAnimation()
shrinking!.isReversed = true

// Disable gesture until reverse closing animation finishes.
gesture.isEnabled = false
shrinking!.addCompletion { [unowned self] (pos) in
  self.didCancelDismissalTransition()
  gesture.isEnabled = true
}
shrinking!.startAnimation()

5. Dismissing

If you're interested in a more visual guide to '5 Phases of Interaction', checkout MobileConf/slides

Weird Bugs