Commit f371f1db by Daniel Dahan

Fixed an issue where using child view controllers would break and transition animations.

parent d5316bd6
Pod::Spec.new do |s| Pod::Spec.new do |s|
s.name = 'Motion' s.name = 'Motion'
s.version = '1.0.7' s.version = '1.0.8'
s.license = 'BSD-3-Clause' s.license = 'BSD-3-Clause'
s.summary = 'Seamless animations and transitions in Swift.' s.summary = 'Seamless animations and transitions in Swift.'
s.homepage = 'http://cosmicmind.com' s.homepage = 'http://cosmicmind.com'
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>FMWK</string> <string>FMWK</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>1.0.7</string> <string>1.0.8</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string> <string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSPrincipalClass</key> <key>NSPrincipalClass</key>
......
...@@ -173,7 +173,7 @@ extension UIViewController { ...@@ -173,7 +173,7 @@ extension UIViewController {
- Returns: An optional UIViewControllerAnimatedTransitioning. - Returns: An optional UIViewControllerAnimatedTransitioning.
*/ */
open func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? { open func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return isMotionEnabled ? Motion(isPresenting: true, isContainer: false) : nil return isMotionEnabled ? PresentingMotion(isPresenting: true, isContainer: false) : nil
} }
/** /**
...@@ -182,7 +182,7 @@ extension UIViewController { ...@@ -182,7 +182,7 @@ extension UIViewController {
- Returns: An optional UIViewControllerAnimatedTransitioning. - Returns: An optional UIViewControllerAnimatedTransitioning.
*/ */
open func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? { open func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return isMotionEnabled ? Motion(isPresenting: false, isContainer: false) : nil return isMotionEnabled ? DismissingMotion(isPresenting: true, isContainer: false) : nil
} }
/** /**
...@@ -330,9 +330,15 @@ public protocol MotionDelegate { ...@@ -330,9 +330,15 @@ public protocol MotionDelegate {
@objc @objc
optional func motionDelayTransitionByTimeInterval(motion: Motion) -> TimeInterval optional func motionDelayTransitionByTimeInterval(motion: Motion) -> TimeInterval
@objc
optional func motionWillBeginPresentation(presentationController: UIPresentationController)
@objc
optional func motionAnimateAlongsideTransition(presentationController: UIPresentationController)
} }
open class Motion: NSObject { open class MotionAnimator: NSObject {
/// A boolean indicating whether Motion is presenting a view controller. /// A boolean indicating whether Motion is presenting a view controller.
open fileprivate(set) var isPresenting: Bool open fileprivate(set) var isPresenting: Bool
...@@ -396,11 +402,6 @@ open class Motion: NSObject { ...@@ -396,11 +402,6 @@ open class Motion: NSObject {
return Motion.subviews(of: fromView) return Motion.subviews(of: fromView)
} }
/// A time value to delay the transition animation by.
fileprivate var delayTransitionByTimeInterval: TimeInterval {
return fromViewController.motionDelegate?.motionDelayTransitionByTimeInterval?(motion: self) ?? 0
}
/// The default initializer. /// The default initializer.
public override init() { public override init() {
isPresenting = false isPresenting = false
...@@ -503,7 +504,7 @@ open class Motion: NSObject { ...@@ -503,7 +504,7 @@ open class Motion: NSObject {
} }
} }
extension Motion: UIViewControllerAnimatedTransitioning { extension MotionAnimator: UIViewControllerAnimatedTransitioning {
/** /**
The animation method that is used to coordinate the transition. The animation method that is used to coordinate the transition.
- Parameter using transitionContext: A UIViewControllerContextTransitioning. - Parameter using transitionContext: A UIViewControllerContextTransitioning.
...@@ -511,21 +512,6 @@ extension Motion: UIViewControllerAnimatedTransitioning { ...@@ -511,21 +512,6 @@ extension Motion: UIViewControllerAnimatedTransitioning {
@objc(animateTransition:) @objc(animateTransition:)
open func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { open func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
self.transitionContext = transitionContext self.transitionContext = transitionContext
fromViewController.motionDelegate?.motion?(motion: self, willTransition: fromView, toView: toView)
Motion.delay(delayTransitionByTimeInterval) { [weak self] in
guard let s = self else {
return
}
s.prepareContainerView()
s.prepareTransitionSnapshot()
s.prepareTransitionPairs()
s.prepareTransitionView()
s.prepareTransitionBackgroundView()
s.prepareToView()
s.prepareTransitionAnimation()
}
} }
/** /**
...@@ -539,66 +525,7 @@ extension Motion: UIViewControllerAnimatedTransitioning { ...@@ -539,66 +525,7 @@ extension Motion: UIViewControllerAnimatedTransitioning {
} }
} }
extension Motion { extension MotionAnimator {
/// Prepares the containerView.
fileprivate func prepareContainerView() {
containerView = transitionContext.containerView
}
/// Prepares the transitionSnapshot.
fileprivate func prepareTransitionSnapshot() {
transitionSnapshot = fromView.transitionSnapshot(afterUpdates: true, shouldHide: false)
transitionSnapshot.frame = fromView.frame
containerView.insertSubview(transitionSnapshot, aboveSubview: fromView)
}
/// Prepares the transitionPairs.
fileprivate func prepareTransitionPairs() {
for from in fromSubviews {
for to in toSubviews {
guard to.motionIdentifier == from.motionIdentifier else {
continue
}
transitionPairs.append((from, to))
}
}
}
/// Prepares the transitionView.
fileprivate func prepareTransitionView() {
transitionView.frame = toView.bounds
transitionView.isUserInteractionEnabled = false
containerView.insertSubview(transitionView, belowSubview: transitionSnapshot)
}
/// Prepares the transitionBackgroundView.
fileprivate func prepareTransitionBackgroundView() {
transitionBackgroundView.backgroundColor = isPresenting ? .clear : fromView.backgroundColor ?? .clear
transitionBackgroundView.frame = transitionView.bounds
transitionView.addSubview(transitionBackgroundView)
}
/// Prepares the toView.
fileprivate func prepareToView() {
toView.isHidden = isPresenting
containerView.insertSubview(toView, belowSubview: transitionView)
toView.frame = fromView.frame
toView.updateConstraints()
toView.setNeedsLayout()
toView.layoutIfNeeded()
}
/// Prepares the transition animation.
fileprivate func prepareTransitionAnimation() {
addTransitionAnimations()
addBackgroundAnimation()
cleanUpAnimation()
removeTransitionSnapshot()
}
}
extension Motion {
/// Adds the available transition animations. /// Adds the available transition animations.
fileprivate func addTransitionAnimations() { fileprivate func addTransitionAnimations() {
for (from, to) in transitionPairs { for (from, to) in transitionPairs {
...@@ -674,26 +601,7 @@ extension Motion { ...@@ -674,26 +601,7 @@ extension Motion {
} }
} }
extension Motion { extension MotionAnimator {
/**
Creates a CAAnimationGroup.
- Parameter animations: An Array of CAAnimation objects.
- Parameter timingFunction: An MotionAnimationTimingFunction value.
- Parameter duration: An animation duration time for the group.
- Returns: A CAAnimationGroup.
*/
open class func animate(group animations: [CAAnimation], timingFunction: MotionAnimationTimingFunction = .easeInEaseOut, duration: CFTimeInterval = 0.5) -> CAAnimationGroup {
let group = CAAnimationGroup()
group.fillMode = MotionAnimationFillModeToValue(mode: .forwards)
group.isRemovedOnCompletion = false
group.animations = animations
group.duration = duration
group.timingFunction = MotionAnimationTimingFunctionToValue(timingFunction: timingFunction)
return group
}
}
extension Motion {
/** /**
Calculates the animation delay time based on the given Array of MotionAnimations. Calculates the animation delay time based on the given Array of MotionAnimations.
- Parameter animations: An Array of MotionAnimations. - Parameter animations: An Array of MotionAnimations.
...@@ -752,6 +660,115 @@ extension Motion { ...@@ -752,6 +660,115 @@ extension Motion {
} }
} }
open class Motion: MotionAnimator {
/// A time value to delay the transition animation by.
fileprivate var delayTransitionByTimeInterval: TimeInterval {
return fromViewController.motionDelegate?.motionDelayTransitionByTimeInterval?(motion: self) ?? 0
}
/**
The animation method that is used to coordinate the transition.
- Parameter using transitionContext: A UIViewControllerContextTransitioning.
*/
@objc(animateTransition:)
open override func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
super.animateTransition(using: transitionContext)
fromViewController.motionDelegate?.motion?(motion: self, willTransition: fromView, toView: toView)
Motion.delay(delayTransitionByTimeInterval) { [weak self] in
guard let s = self else {
return
}
s.prepareContainerView()
s.prepareTransitionSnapshot()
s.prepareTransitionPairs()
s.prepareTransitionView()
s.prepareTransitionBackgroundView()
s.prepareToView()
s.prepareTransitionAnimation()
}
}
/// Prepares the toView.
fileprivate func prepareToView() {
toView.isHidden = isPresenting
containerView.insertSubview(toView, belowSubview: transitionView)
toView.frame = fromView.frame
toView.updateConstraints()
toView.setNeedsLayout()
toView.layoutIfNeeded()
}
}
extension Motion {
/// Prepares the containerView.
fileprivate func prepareContainerView() {
containerView = transitionContext.containerView
}
/// Prepares the transitionSnapshot.
fileprivate func prepareTransitionSnapshot() {
transitionSnapshot = fromView.transitionSnapshot(afterUpdates: true, shouldHide: false)
transitionSnapshot.frame = fromView.frame
containerView.addSubview(transitionSnapshot)
}
/// Prepares the transitionPairs.
fileprivate func prepareTransitionPairs() {
for from in fromSubviews {
for to in toSubviews {
guard to.motionIdentifier == from.motionIdentifier else {
continue
}
transitionPairs.append((from, to))
}
}
}
/// Prepares the transitionView.
fileprivate func prepareTransitionView() {
transitionView.frame = toView.bounds
transitionView.isUserInteractionEnabled = false
containerView.insertSubview(transitionView, belowSubview: transitionSnapshot)
}
/// Prepares the transitionBackgroundView.
fileprivate func prepareTransitionBackgroundView() {
transitionBackgroundView.backgroundColor = isPresenting ? .clear : fromView.backgroundColor ?? .clear
transitionBackgroundView.frame = transitionView.bounds
transitionView.addSubview(transitionBackgroundView)
}
/// Prepares the transition animation.
fileprivate func prepareTransitionAnimation() {
addTransitionAnimations()
addBackgroundAnimation()
cleanUpAnimation()
removeTransitionSnapshot()
}
}
extension Motion {
/**
Creates a CAAnimationGroup.
- Parameter animations: An Array of CAAnimation objects.
- Parameter timingFunction: An MotionAnimationTimingFunction value.
- Parameter duration: An animation duration time for the group.
- Returns: A CAAnimationGroup.
*/
open class func animate(group animations: [CAAnimation], timingFunction: MotionAnimationTimingFunction = .easeInEaseOut, duration: CFTimeInterval = 0.5) -> CAAnimationGroup {
let group = CAAnimationGroup()
group.fillMode = MotionAnimationFillModeToValue(mode: .forwards)
group.isRemovedOnCompletion = false
group.animations = animations
group.duration = duration
group.timingFunction = MotionAnimationTimingFunctionToValue(timingFunction: timingFunction)
return group
}
}
extension Motion { extension Motion {
/// Cleans up the animation transition. /// Cleans up the animation transition.
fileprivate func cleanUpAnimation() { fileprivate func cleanUpAnimation() {
...@@ -798,3 +815,17 @@ extension Motion { ...@@ -798,3 +815,17 @@ extension Motion {
transitionContext.completeTransition(!transitionContext.transitionWasCancelled) transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
} }
} }
open class PresentingMotion: Motion {}
open class DismissingMotion: Motion {
/// Prepares the toView.
fileprivate override func prepareToView() {
toView.isHidden = true
toView.frame = fromView.frame
toView.updateConstraints()
toView.setNeedsLayout()
toView.layoutIfNeeded()
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment