Commit 1e63fdbd by Daniel Dahan

development: added transitionView to MotionTransition animations

parent e46c5a84
...@@ -32,6 +32,39 @@ import UIKit ...@@ -32,6 +32,39 @@ import UIKit
/// Grid extension for UIView. /// Grid extension for UIView.
extension UIView { extension UIView {
/// A property that accesses the backing layer's masksToBounds.
@IBInspectable
open var masksToBounds: Bool {
get {
return layer.masksToBounds
}
set(value) {
layer.masksToBounds = value
}
}
/// A property that accesses the backing layer's opacity.
@IBInspectable
open var opacity: Float {
get {
return layer.opacity
}
set(value) {
layer.opacity = value
}
}
/// A property that accesses the backing layer's anchorPoint.
@IBInspectable
open var anchorPoint: CGPoint {
get {
return layer.anchorPoint
}
set(value) {
layer.anchorPoint = value
}
}
/// A property that accesses the frame.origin.x property. /// A property that accesses the frame.origin.x property.
@IBInspectable @IBInspectable
open var x: CGFloat { open var x: CGFloat {
......
...@@ -52,6 +52,7 @@ public enum MotionAnimationKeyPath: String { ...@@ -52,6 +52,7 @@ public enum MotionAnimationKeyPath: String {
case zPosition case zPosition
case width = "bounds.size.width" case width = "bounds.size.width"
case height = "bounds.size.height" case height = "bounds.size.height"
case size = "bounds.size"
} }
public enum MotionAnimation { public enum MotionAnimation {
...@@ -87,6 +88,7 @@ public enum MotionAnimation { ...@@ -87,6 +88,7 @@ public enum MotionAnimation {
case zPosition(Int) case zPosition(Int)
case width(CGFloat) case width(CGFloat)
case height(CGFloat) case height(CGFloat)
case size(CGSize)
} }
extension CALayer { extension CALayer {
...@@ -190,6 +192,22 @@ extension CALayer { ...@@ -190,6 +192,22 @@ extension CALayer {
var tf = timingFunction var tf = timingFunction
var d = duration var d = duration
var px: CGFloat = s.position.x
var py: CGFloat = s.position.y
for v in animations {
switch v {
case let .x(x):
px = x + w / 2
case let .y(y):
py = y + h / 2
case let .point(x, y):
px = x + w / 2
py = y + h / 2
default:break
}
}
for v in animations { for v in animations {
switch v { switch v {
case let .timingFunction(timingFunction): case let .timingFunction(timingFunction):
...@@ -239,12 +257,9 @@ extension CALayer { ...@@ -239,12 +257,9 @@ extension CALayer {
a.append(Motion.translateY(to: to)) a.append(Motion.translateY(to: to))
case let .translateZ(to): case let .translateZ(to):
a.append(Motion.translateZ(to: to)) a.append(Motion.translateZ(to: to))
case let .x(x): case let .x(_), .y(_), .point(_, _):
a.append(Motion.position(to: CGPoint(x: x + w / 2, y: s.position.y))) let position = Motion.position(to: CGPoint(x: px, y: py))
case let .y(y): a.append(position)
a.append(Motion.position(to: CGPoint(x: s.position.x, y: y + h / 2)))
case let .point(x, y):
a.append(Motion.position(to: CGPoint(x: x + w / 2, y: y + h / 2)))
case let .position(x, y): case let .position(x, y):
a.append(Motion.position(to: CGPoint(x: x, y: y))) a.append(Motion.position(to: CGPoint(x: x, y: y)))
case let .shadow(path): case let .shadow(path):
...@@ -261,6 +276,8 @@ extension CALayer { ...@@ -261,6 +276,8 @@ extension CALayer {
a.append(Motion.width(w)) a.append(Motion.width(w))
case let .height(h): case let .height(h):
a.append(Motion.height(h)) a.append(Motion.height(h))
case let .size(size):
a.append(Motion.size(size))
default:break default:break
} }
} }
...@@ -523,6 +540,18 @@ extension Motion { ...@@ -523,6 +540,18 @@ extension Motion {
/** /**
Creates a CABasicAnimation for the position key path. Creates a CABasicAnimation for the position key path.
- Parameter x: A CGFloat.
- Parameter y: A CGFloat.
- Returns: A CABasicAnimation.
*/
public static func position(x: CGFloat, y: CGFloat) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: .position)
animation.toValue = NSValue(cgPoint: CGPoint(x: x, y: y))
return animation
}
/**
Creates a CABasicAnimation for the position key path.
- Parameter to point: A CGPoint. - Parameter to point: A CGPoint.
- Returns: A CABasicAnimation. - Returns: A CABasicAnimation.
*/ */
...@@ -586,4 +615,15 @@ extension Motion { ...@@ -586,4 +615,15 @@ extension Motion {
animation.toValue = NSNumber(floatLiteral: Double(height)) animation.toValue = NSNumber(floatLiteral: Double(height))
return animation return animation
} }
/**
Creates a CABasicaAnimation for the height key path.
- Parameter size: A CGSize.
- Returns: A CABasicAnimation.
*/
public static func size(_ size: CGSize) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: .size)
animation.toValue = NSValue(cgSize: size)
return animation
}
} }
...@@ -123,7 +123,7 @@ extension UIView { ...@@ -123,7 +123,7 @@ extension UIView {
open class MotionTransitionPresentationController: UIPresentationController { open class MotionTransitionPresentationController: UIPresentationController {
open override func presentationTransitionWillBegin() { open override func presentationTransitionWillBegin() {
guard let containerView = containerView else { guard nil != containerView else {
return return
} }
...@@ -139,7 +139,7 @@ open class MotionTransitionPresentationController: UIPresentationController { ...@@ -139,7 +139,7 @@ open class MotionTransitionPresentationController: UIPresentationController {
} }
open override func dismissalTransitionWillBegin() { open override func dismissalTransitionWillBegin() {
guard let containerView = containerView else { guard nil != containerView else {
return return
} }
...@@ -161,62 +161,10 @@ open class MotionTransitionPresentationController: UIPresentationController { ...@@ -161,62 +161,10 @@ open class MotionTransitionPresentationController: UIPresentationController {
open class MotionTransitionDelegate: NSObject { open class MotionTransitionDelegate: NSObject {
open var isPresenting = false open var isPresenting = false
open var transitionContext: UIViewControllerContextTransitioning!
open var containerView: UIView!
open var toView: UIView!
open var toViews: [UIView] {
var views: [UIView] = 0 < toViewController.view.motionTransitionIdentifier.utf16.count ? [toViewController.view] : []
subviews(of: toViewController.view, views: &views)
return views
}
open var toViewController: UIViewController! open var toViewController: UIViewController!
open var toViewStartFrame: CGRect!
open var toViewFinalFrame: CGRect!
open var fromView: UIView!
open var fromViews: [UIView] {
var views: [UIView] = 0 < fromViewController.view.motionTransitionIdentifier.utf16.count ? [fromViewController.view] : []
subviews(of: fromViewController.view, views: &views)
return views
}
open var fromViewController: UIViewController! open var fromViewController: UIViewController!
open var fromViewFinalFrame: CGRect!
}
extension MotionTransitionDelegate {
@objc(animateTransition:)
open func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
}
@objc(transitionDuration:)
open func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
return 0.25
}
open func animationEnded(_ transitionCompleted: Bool) {
// print("MotionTransitionAnimator", #function)
}
}
extension MotionTransitionDelegate {
fileprivate func subviews(of view: UIView, views: inout [UIView]) {
for v in view.subviews {
if 0 < v.motionTransitionIdentifier.utf16.count {
views.append(v)
}
subviews(of: v, views: &views)
}
}
} }
extension MotionTransitionDelegate: UIViewControllerTransitioningDelegate { extension MotionTransitionDelegate: UIViewControllerTransitioningDelegate {
...@@ -266,36 +214,32 @@ extension MotionTransitionDelegate: UITabBarControllerDelegate { ...@@ -266,36 +214,32 @@ extension MotionTransitionDelegate: UITabBarControllerDelegate {
} }
} }
open class MotionTransitionInteractiveDelegate: UIPercentDrivenInteractiveTransition { open class MotionTransitionAnimator: MotionTransitionDelegate {
open var isPresenting = false
open var transitionContext: UIViewControllerContextTransitioning! open var transitionContext: UIViewControllerContextTransitioning!
open var containerView: UIView! open var delay: TimeInterval = 0
open var duration: TimeInterval = 0
open var toView: UIView!
open var toViewController: UIViewController!
open var toViewStartFrame: CGRect!
open var toViewFinalFrame: CGRect!
open var fromView: UIView! open var containerView: UIView!
open var fromViewController: UIViewController! open var transitionView = UIView()
open var fromViewFinalFrame: CGRect!
open var panGesture: UIPanGestureRecognizer!
@objc(startInteractiveTransition:)
open override func startInteractiveTransition(_ transitionContext: UIViewControllerContextTransitioning) {
super.startInteractiveTransition(transitionContext)
guard let tView = transitionContext.view(forKey: .to) else { public var toViews: [UIView] {
return var views: [UIView] = 0 < toViewController.view.motionTransitionIdentifier.utf16.count ? [toViewController.view] : []
subviews(of: toViewController.view, views: &views)
return views
} }
guard let tVC = transitionContext.viewController(forKey: .to) else { public var fromViews: [UIView] {
return var views: [UIView] = 0 < fromViewController.view.motionTransitionIdentifier.utf16.count ? [fromViewController.view] : []
subviews(of: fromViewController.view, views: &views)
return views
} }
}
guard let fView = transitionContext.view(forKey: .from) else { extension MotionTransitionAnimator: UIViewControllerAnimatedTransitioning {
@objc(animateTransition:)
open func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
guard let tVC = transitionContext.viewController(forKey: .to) else {
return return
} }
...@@ -306,166 +250,79 @@ open class MotionTransitionInteractiveDelegate: UIPercentDrivenInteractiveTransi ...@@ -306,166 +250,79 @@ open class MotionTransitionInteractiveDelegate: UIPercentDrivenInteractiveTransi
self.transitionContext = transitionContext self.transitionContext = transitionContext
containerView = transitionContext.containerView containerView = transitionContext.containerView
containerView.addSubview(transitionView)
transitionView.frame = containerView.bounds
toView = tView
toViewController = tVC toViewController = tVC
fromView = fView
fromViewController = fVC fromViewController = fVC
toViewStartFrame = transitionContext.initialFrame(for: toViewController)
toViewFinalFrame = transitionContext.finalFrame(for: toViewController)
fromViewFinalFrame = transitionContext.finalFrame(for: fromViewController)
preparePanGesture()
}
open func animationEnded(_ transitionCompleted: Bool) {
// print("MotionTransitionAnimator", #function)
} }
}
extension MotionTransitionInteractiveDelegate { @objc(transitionDuration:)
fileprivate func preparePanGesture() { open func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
panGesture = UIPanGestureRecognizer(target: self, action: #selector(handlePanGesture(recognizer:))) return delay + duration
panGesture.maximumNumberOfTouches = 1
containerView.addGestureRecognizer(panGesture)
} }
} }
extension MotionTransitionInteractiveDelegate { extension MotionTransitionDelegate {
@objc fileprivate func subviews(of view: UIView, views: inout [UIView]) {
fileprivate func handlePanGesture(recognizer: UIPanGestureRecognizer) { for v in view.subviews {
switch recognizer.state { if 0 < v.motionTransitionIdentifier.utf16.count {
case .began: views.append(v)
panGesture.setTranslation(.zero, in: containerView)
case .changed:
let translation = panGesture.translation(in: containerView)
/**
Compute how far the gesture recognizer tranveled on the
vertical axis.
*/
let percentageComplete = fabs(translation.y / containerView.bounds.height)
update(percentageComplete)
case .ended:
finish()
containerView.removeGestureRecognizer(panGesture)
default:break
} }
subviews(of: v, views: &views)
} }
}
open class MotionTransitionAnimator: MotionTransitionDelegate, UIViewControllerAnimatedTransitioning {
@objc(animateTransition:)
open override func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
// guard let tView = transitionContext.view(forKey: .to) else {
// return
// }
guard let tVC = transitionContext.viewController(forKey: .to) else {
return
} }
// guard let fView = transitionContext.view(forKey: .from) else { fileprivate func snapshotView(for view: UIView) -> UIView {
// return view.isHidden = false
// }
guard let fVC = transitionContext.viewController(forKey: .from) else { // capture a snapshot without cornerRadius
return let oldCornerRadius = view.cornerRadius
} view.cornerRadius = 0
let v = view.snapshotView(afterScreenUpdates: false)!
self.transitionContext = transitionContext view.cornerRadius = oldCornerRadius
containerView = transitionContext.containerView
// toView = tView let contentView = v.subviews.first!
toViewController = tVC contentView.cornerRadius = view.cornerRadius
contentView.masksToBounds = true
// fromView = fView v.motionTransitionIdentifier = view.motionTransitionIdentifier
fromViewController = fVC v.cornerRadius = view.cornerRadius
v.zPosition = view.zPosition
v.opacity = view.opacity
v.isOpaque = view.isOpaque
v.anchorPoint = view.anchorPoint
v.layer.masksToBounds = view.layer.masksToBounds
v.borderColor = view.borderColor
v.borderWidth = view.borderWidth
v.shadowRadius = view.shadowRadius
v.shadowOpacity = view.shadowOpacity
v.shadowColor = view.shadowColor
v.shadowOffset = view.shadowOffset
toViewStartFrame = transitionContext.initialFrame(for: toViewController) v.layer.transform = view.layer.transform
toViewFinalFrame = transitionContext.finalFrame(for: toViewController)
fromViewFinalFrame = transitionContext.finalFrame(for: fromViewController)
var duration = transitionDuration(using: nil) view.isHidden = true
transitionContext.containerView.addSubview(toViewController.view) return v
for v in toViews {
if 0 < v.motionTransitionIdentifier.utf16.count {
for a in v.motionTransitionAnimations {
switch a {
case let .duration(dur):
if dur > duration {
duration = dur
}
default:break
}
}
v.motion(v.motionTransitionAnimations)
}
}
Motion.delay(duration) {
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
}
} }
} }
open class MotionTransitionPresentedAnimator: MotionTransitionDelegate, UIViewControllerAnimatedTransitioning { open class MotionTransitionPresentedAnimator: MotionTransitionAnimator {
@objc(animateTransition:) @objc(animateTransition:)
open override func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { open override func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
// guard let tView = transitionContext.view(forKey: .to) else { super.animateTransition(using: transitionContext)
// return
// }
guard let tVC = transitionContext.viewController(forKey: .to) else {
return
}
// guard let fView = transitionContext.view(forKey: .from) else {
// return
// }
guard let fVC = transitionContext.viewController(forKey: .from) else {
return
}
self.transitionContext = transitionContext
containerView = transitionContext.containerView
// toView = tView for toView in toViews {
toViewController = tVC for fromView in fromViews {
if toView.motionTransitionIdentifier == fromView.motionTransitionIdentifier {
// fromView = fView
fromViewController = fVC
toViewStartFrame = transitionContext.initialFrame(for: toViewController)
toViewFinalFrame = transitionContext.finalFrame(for: toViewController)
fromViewFinalFrame = transitionContext.finalFrame(for: fromViewController)
var delay: TimeInterval = 0
var duration = transitionDuration(using: nil)
transitionContext.containerView.addSubview(toViewController.view)
for v in toViews {
for v2 in fromViews {
if v.motionTransitionIdentifier == v2.motionTransitionIdentifier {
var t: TimeInterval = 0 var t: TimeInterval = 0
var d: TimeInterval = 0 var d: TimeInterval = 0
var a = [CABasicAnimation]() var a = [CABasicAnimation]()
var tf = MotionAnimationTimingFunction.easeInEaseOut var tf = MotionAnimationTimingFunction.easeInEaseOut
var w: CGFloat = 0 for ta in toView.motionTransitionAnimations {
var h: CGFloat = 0
for ta in v.motionTransitionAnimations {
switch ta { switch ta {
case let .delay(time): case let .delay(time):
if time > delay { if time > delay {
...@@ -477,55 +334,38 @@ open class MotionTransitionPresentedAnimator: MotionTransitionDelegate, UIViewCo ...@@ -477,55 +334,38 @@ open class MotionTransitionPresentedAnimator: MotionTransitionDelegate, UIViewCo
duration = time duration = time
} }
d = time d = time
case let .width(width):
w = width
case let .height(height):
h = height
default:break default:break
} }
} }
// var w: CGFloat = toView.bounds.width
// var h: CGFloat = toView.bounds.height
// var px: CGFloat = toView.position.x + w / 2
// var py: CGFloat = toView.position.y + h / 2
// a.append(Motion.position(x: px, y: py))
// a.append(Motion.width(w))
// a.append(Motion.height(h))
var px: CGFloat = v.position.x // let rotate = Motion.rotate(angle: toView.layer.value(forKeyPath: MotionAnimationKeyPath.rotation.rawValue) as? CGFloat ?? 0)
var py: CGFloat = v.position.y // rotate.fromValue = fromView.layer.value(forKeyPath: MotionAnimationKeyPath.rotation.rawValue)
// a.append(rotate)
for ta in v.motionTransitionAnimations { a.append(Motion.background(color: toView.backgroundColor ?? .clear))
switch ta { // a.append(Motion.corner(radius: toView.cornerRadius))
case let .x(x):
px = x + w / 2 let snapshot = snapshotView(for: fromView)
case let .y(y): snapshot.isHidden = false
py = y + h / 2 snapshot.bounds = fromView.bounds
case let .point(x, y): snapshot.position = fromView.superview?.convert(fromView.position, to: nil) ?? fromView.position
px = x + w / 2 transitionView.addSubview(snapshot)
py = y + h / 2
default:break
}
}
Motion.delay(t) { Motion.delay(t) {
for ta in v.motionTransitionAnimations { for ta in toView.motionTransitionAnimations {
switch ta { switch ta {
case let .timingFunction(timingFunction): case let .timingFunction(timingFunction):
tf = timingFunction tf = timingFunction
case let .rotate(angle):
let rotate = Motion.rotate(angle: angle)
let radians = CGFloat(atan2f(Float(v2.transform.b), Float(v2.transform.a)))
rotate.fromValue = v2.layer.value(forKeyPath: MotionAnimationKeyPath.rotation.rawValue)
a.append(rotate)
case let .backgroundColor(color):
a.append(Motion.background(color: color))
case let .corners(radius):
a.append(Motion.corner(radius: radius))
case let .x(_), .y(_), .point(_, _):
a.append(Motion.position(to: CGPoint(x: px, y: py)))
case let .position(x, y):
a.append(Motion.position(to: CGPoint(x: x, y: y)))
case let .shadow(path): case let .shadow(path):
a.append(Motion.shadow(path: path)) a.append(Motion.shadow(path: path))
case let .width(w):
a.append(Motion.width(w))
case let .height(h):
a.append(Motion.height(h))
default:break default:break
} }
} }
...@@ -535,53 +375,31 @@ open class MotionTransitionPresentedAnimator: MotionTransitionDelegate, UIViewCo ...@@ -535,53 +375,31 @@ open class MotionTransitionPresentedAnimator: MotionTransitionDelegate, UIViewCo
g.isRemovedOnCompletion = false g.isRemovedOnCompletion = false
g.timingFunction = MotionAnimationTimingFunctionToValue(timingFunction: tf) g.timingFunction = MotionAnimationTimingFunctionToValue(timingFunction: tf)
v.animate(g) snapshot.animate(g)
} }
} }
} }
} }
Motion.delay(delay + duration) { Motion.delay(transitionDuration(using: transitionContext)) { [weak self] in
defer {
transitionContext.completeTransition(!transitionContext.transitionWasCancelled) transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
} }
}
}
open class MotionTransitionDismissedAnimator: MotionTransitionDelegate, UIViewControllerAnimatedTransitioning {
@objc(animateTransition:)
open override func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
// guard let tView = transitionContext.view(forKey: .to) else {
// return
// }
guard let tVC = transitionContext.viewController(forKey: .to) else { guard let s = self else {
return return
} }
// guard let fView = transitionContext.view(forKey: .from) else { // s.transitionView.removeFromSuperview()
// return s.containerView.addSubview(s.toViewController.view)
// }
guard let fVC = transitionContext.viewController(forKey: .from) else {
return
} }
}
}
self.transitionContext = transitionContext open class MotionTransitionDismissedAnimator: MotionTransitionAnimator {
@objc(animateTransition:)
containerView = transitionContext.containerView open override func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
super.animateTransition(using: transitionContext)
// toView = tView
toViewController = tVC
// fromView = fView
fromViewController = fVC
toViewStartFrame = transitionContext.initialFrame(for: toViewController)
toViewFinalFrame = transitionContext.finalFrame(for: toViewController)
fromViewFinalFrame = transitionContext.finalFrame(for: fromViewController)
var delay: TimeInterval = 0
var duration = transitionDuration(using: nil)
for v in fromViews { for v in fromViews {
for v2 in toViews { for v2 in toViews {
...@@ -606,22 +424,22 @@ open class MotionTransitionDismissedAnimator: MotionTransitionDelegate, UIViewCo ...@@ -606,22 +424,22 @@ open class MotionTransitionDismissedAnimator: MotionTransitionDelegate, UIViewCo
d = time d = time
case let .timingFunction(timingFunction): case let .timingFunction(timingFunction):
tf = timingFunction tf = timingFunction
case let .rotate(angle): case .rotate(_):
let radians = CGFloat(atan2f(Float(v2.transform.b), Float(v2.transform.a))) let radians = CGFloat(atan2f(Float(v2.transform.b), Float(v2.transform.a)))
let rotate = Motion.rotate(angle: radians * 180 / CGFloat(M_PI)) let rotate = Motion.rotate(angle: radians * 180 / CGFloat(M_PI))
rotate.fromValue = v.layer.value(forKeyPath: MotionAnimationKeyPath.rotation.rawValue) rotate.fromValue = v.layer.value(forKeyPath: MotionAnimationKeyPath.rotation.rawValue)
a.append(rotate) a.append(rotate)
case let .backgroundColor(color): case .backgroundColor(_):
a.append(Motion.background(color: .clear)) a.append(Motion.background(color: .clear))
case let .corners(radius): case .corners(_):
a.append(Motion.corner(radius: v2.cornerRadius)) a.append(Motion.corner(radius: v2.cornerRadius))
case let .x(_), .y(_), .point(_, _), .position(_, _): case .x(_), .y(_), .point(_, _), .position(_, _):
a.append(Motion.position(to: nil == v2.superview ? v2.position : v2.superview!.convert(v2.position, to: nil))) a.append(Motion.position(to: nil == v2.superview ? v2.position : v2.superview!.convert(v2.position, to: nil)))
case let .shadow(path): case let .shadow(path):
a.append(Motion.shadow(path: path)) a.append(Motion.shadow(path: path))
case let .width(w): case .width(_):
a.append(Motion.width(v2.bounds.width)) a.append(Motion.width(v2.bounds.width))
case let .height(h): case .height(_):
a.append(Motion.height(v2.bounds.height)) a.append(Motion.height(v2.bounds.height))
default:break default:break
} }
...@@ -651,3 +469,94 @@ open class MotionTransitionInteractiveAnimator: MotionTransitionInteractiveDeleg ...@@ -651,3 +469,94 @@ open class MotionTransitionInteractiveAnimator: MotionTransitionInteractiveDeleg
} }
} }
open class MotionTransitionInteractiveDelegate: UIPercentDrivenInteractiveTransition {
open var isPresenting = false
open var transitionContext: UIViewControllerContextTransitioning!
open var containerView: UIView!
open var toView: UIView!
open var toViewController: UIViewController!
open var toViewStartFrame: CGRect!
open var toViewFinalFrame: CGRect!
open var fromView: UIView!
open var fromViewController: UIViewController!
open var fromViewFinalFrame: CGRect!
open var panGesture: UIPanGestureRecognizer!
@objc(startInteractiveTransition:)
open override func startInteractiveTransition(_ transitionContext: UIViewControllerContextTransitioning) {
super.startInteractiveTransition(transitionContext)
guard let tView = transitionContext.view(forKey: .to) else {
return
}
guard let tVC = transitionContext.viewController(forKey: .to) else {
return
}
guard let fView = transitionContext.view(forKey: .from) else {
return
}
guard let fVC = transitionContext.viewController(forKey: .from) else {
return
}
self.transitionContext = transitionContext
containerView = transitionContext.containerView
toView = tView
toViewController = tVC
fromView = fView
fromViewController = fVC
toViewStartFrame = transitionContext.initialFrame(for: toViewController)
toViewFinalFrame = transitionContext.finalFrame(for: toViewController)
fromViewFinalFrame = transitionContext.finalFrame(for: fromViewController)
preparePanGesture()
}
open func animationEnded(_ transitionCompleted: Bool) {
// print("MotionTransitionAnimator", #function)
}
}
extension MotionTransitionInteractiveDelegate {
fileprivate func preparePanGesture() {
panGesture = UIPanGestureRecognizer(target: self, action: #selector(handlePanGesture(recognizer:)))
panGesture.maximumNumberOfTouches = 1
containerView.addGestureRecognizer(panGesture)
}
}
extension MotionTransitionInteractiveDelegate {
@objc
fileprivate func handlePanGesture(recognizer: UIPanGestureRecognizer) {
switch recognizer.state {
case .began:
panGesture.setTranslation(.zero, in: containerView)
case .changed:
let translation = panGesture.translation(in: containerView)
/**
Compute how far the gesture recognizer tranveled on the
vertical axis.
*/
let percentageComplete = fabs(translation.y / containerView.bounds.height)
update(percentageComplete)
case .ended:
finish()
containerView.removeGestureRecognizer(panGesture)
default:break
}
}
}
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