forked from shadowfacts/Tusker
90 lines
3.5 KiB
Swift
90 lines
3.5 KiB
Swift
//
|
|
// DuckAnimationController.swift
|
|
// Duckable
|
|
//
|
|
// Created by Shadowfacts on 11/7/22.
|
|
//
|
|
|
|
import UIKit
|
|
|
|
@available(iOS 16.0, *)
|
|
class DuckAnimationController: NSObject, UIViewControllerAnimatedTransitioning {
|
|
let owner: DuckableContainerViewController
|
|
let needsShrinkAnimation: Bool
|
|
|
|
init(owner: DuckableContainerViewController, needsShrinkAnimation: Bool) {
|
|
self.owner = owner
|
|
self.needsShrinkAnimation = needsShrinkAnimation
|
|
}
|
|
|
|
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
|
|
return 0.2
|
|
}
|
|
|
|
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
|
|
guard case .ducked(let duckable, placeholder: let placeholder) = owner.state,
|
|
let presented = transitionContext.viewController(forKey: .from) else {
|
|
transitionContext.completeTransition(false)
|
|
return
|
|
}
|
|
|
|
guard transitionContext.isAnimated else {
|
|
transitionContext.completeTransition(true)
|
|
return
|
|
}
|
|
|
|
let container = transitionContext.containerView
|
|
|
|
|
|
if needsShrinkAnimation {
|
|
|
|
duckable.duckableViewControllerWillAnimateDuck(withDuration: 0.2, afterDelay: 0.2)
|
|
|
|
let presentedFrameInContainer = container.convert(presented.view.bounds, from: presented.view)
|
|
let heightToSlide = container.bounds.height - container.safeAreaInsets.bottom - detentHeight - presentedFrameInContainer.minY
|
|
|
|
let slideAnimator = UIViewPropertyAnimator(duration: 0.4, dampingRatio: 1)
|
|
slideAnimator.addAnimations {
|
|
container.transform = CGAffineTransform(translationX: 0, y: heightToSlide + 10)
|
|
}
|
|
slideAnimator.addCompletion { _ in
|
|
duckable.duckableViewControllerDidFinishAnimatingDuck()
|
|
transitionContext.completeTransition(true)
|
|
}
|
|
slideAnimator.startAnimation()
|
|
|
|
placeholder.view.transform = CGAffineTransform(translationX: 0, y: 10)
|
|
let bounceAnimator = UIViewPropertyAnimator(duration: 0.1, curve: .linear) {
|
|
placeholder.view.transform = .identity
|
|
container.transform = CGAffineTransform(translationX: 0, y: heightToSlide)
|
|
}
|
|
bounceAnimator.startAnimation(afterDelay: 0.3)
|
|
|
|
let fadeAnimator = UIViewPropertyAnimator(duration: 0.1, curve: .linear) {
|
|
presented.view.layer.opacity = 0
|
|
}
|
|
fadeAnimator.startAnimation(afterDelay: 0.3)
|
|
|
|
} else {
|
|
|
|
duckable.duckableViewControllerWillAnimateDuck(withDuration: 0.2, afterDelay: 0)
|
|
|
|
placeholder.view.transform = CGAffineTransform(translationX: 0, y: 10)
|
|
let bounceAnimator = UIViewPropertyAnimator(duration: 0.1, curve: .linear) {
|
|
placeholder.view.transform = .identity
|
|
container.transform = CGAffineTransform(translationX: 0, y: -10)
|
|
}
|
|
bounceAnimator.startAnimation(afterDelay: 0.2)
|
|
|
|
let fadeAnimator = UIViewPropertyAnimator(duration: 0.1, curve: .linear) {
|
|
presented.view.layer.opacity = 0
|
|
}
|
|
fadeAnimator.addCompletion { _ in
|
|
duckable.duckableViewControllerDidFinishAnimatingDuck()
|
|
transitionContext.completeTransition(true)
|
|
}
|
|
fadeAnimator.startAnimation(afterDelay: 0.2)
|
|
}
|
|
}
|
|
}
|