Commit 9ee829f1 by Daniel Dahan

development: updated MotionTransition delegation and animator

parent f4a5cc8c
...@@ -31,9 +31,6 @@ ...@@ -31,9 +31,6 @@
import UIKit import UIKit
open class BottomNavigationController: UITabBarController, UITabBarControllerDelegate { open class BottomNavigationController: UITabBarController, UITabBarControllerDelegate {
/// The transition animation to use when selecting a new tab.
open var motionTransition = MotionTransition.fade
/** /**
An initializer that initializes the object with a NSCoder object. An initializer that initializes the object with a NSCoder object.
- Parameter aDecoder: A NSCoder instance. - Parameter aDecoder: A NSCoder instance.
...@@ -119,7 +116,7 @@ open class BottomNavigationController: UITabBarController, UITabBarControllerDel ...@@ -119,7 +116,7 @@ open class BottomNavigationController: UITabBarController, UITabBarControllerDel
/// Handles transitions when tabBarItems are pressed. /// Handles transitions when tabBarItems are pressed.
open func tabBarController(_ tabBarController: UITabBarController, animationControllerForTransitionFrom fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? { open func tabBarController(_ tabBarController: UITabBarController, animationControllerForTransitionFrom fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return .fade == motionTransition ? FadeMotionTransition() : nil return FadeMotionTransition()
} }
/// Prepares the tabBar. /// Prepares the tabBar.
......
...@@ -191,7 +191,7 @@ open class Button: UIButton, Pulseable { ...@@ -191,7 +191,7 @@ open class Button: UIButton, Pulseable {
let p = point ?? center let p = point ?? center
pulse.expand(point: p) pulse.expand(point: p)
Motion.delay(time: 0.35) { [weak self] in Motion.delay(0.35) { [weak self] in
self?.pulse.contract() self?.pulse.contract()
} }
} }
......
...@@ -243,7 +243,7 @@ open class CollectionReusableView: UICollectionReusableView, Pulseable { ...@@ -243,7 +243,7 @@ open class CollectionReusableView: UICollectionReusableView, Pulseable {
let p = point ?? center let p = point ?? center
pulse.expand(point: p) pulse.expand(point: p)
Motion.delay(time: 0.35) { [weak self] in Motion.delay(0.35) { [weak self] in
self?.pulse.contract() self?.pulse.contract()
} }
} }
......
...@@ -201,7 +201,7 @@ open class CollectionViewCell: UICollectionViewCell, Pulseable { ...@@ -201,7 +201,7 @@ open class CollectionViewCell: UICollectionViewCell, Pulseable {
let p = point ?? center let p = point ?? center
pulse.expand(point: p) pulse.expand(point: p)
Motion.delay(time: 0.35) { [weak self] in Motion.delay(0.35) { [weak self] in
self?.pulse.contract() self?.pulse.contract()
} }
} }
......
...@@ -95,7 +95,7 @@ public struct Motion { ...@@ -95,7 +95,7 @@ public struct Motion {
the animations have completed. the animations have completed.
*/ */
@discardableResult @discardableResult
public static func delay(time: TimeInterval, execute block: @escaping () -> Void) -> MotionDelayCancelBlock? { public static func delay(_ time: TimeInterval, execute block: @escaping () -> Void) -> MotionDelayCancelBlock? {
func asyncAfter(completion: @escaping () -> Void) { func asyncAfter(completion: @escaping () -> Void) {
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + time, execute: completion) DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + time, execute: completion)
...@@ -179,7 +179,7 @@ public struct Motion { ...@@ -179,7 +179,7 @@ public struct Motion {
the animations have completed. the animations have completed.
*/ */
public static func animate(delay time: CFTimeInterval, duration: CFTimeInterval, animations: @escaping (() -> Void), completion: (() -> Void)? = nil) { public static func animate(delay time: CFTimeInterval, duration: CFTimeInterval, animations: @escaping (() -> Void), completion: (() -> Void)? = nil) {
delay(time: time) { delay(time) {
animate(duration: duration, animations: animations, completion: completion) animate(duration: duration, animations: animations, completion: completion)
} }
} }
......
...@@ -168,7 +168,7 @@ extension CALayer { ...@@ -168,7 +168,7 @@ extension CALayer {
} }
} }
Motion.delay(time: t) { [weak self] in Motion.delay(t) { [weak self] in
guard let s = self else { guard let s = self else {
return return
} }
......
...@@ -30,67 +30,176 @@ ...@@ -30,67 +30,176 @@
import UIKit import UIKit
/// A memory reference to the MotionIdentifier instance for UIView extensions. fileprivate var MotionTransitionItemKey: UInt8 = 0
fileprivate var MotionIdentifierKey: UInt8 = 0 fileprivate var MotionTransitionItemControllerKey: UInt8 = 0
fileprivate struct MotionTransitionItem { fileprivate struct MotionTransitionItem {
fileprivate var identifier: String fileprivate var identifier: String
fileprivate var animations: [MotionAnimation] fileprivate var animations: [MotionAnimation]
} }
fileprivate struct MotionTransitionItemController {
fileprivate var delegate: MotionTransitionDelegate
}
extension UIViewController {
// override func transition(from fromViewController: UIViewController, to toViewController: UIViewController, duration: TimeInterval, options: UIViewAnimationOptions = [], animations: (() -> Void)?, completion: ((Bool) -> Void)? = nil) {
//
// }
/// MaterialLayer Reference.
fileprivate var motionTransition: MotionTransitionItemController {
get {
return AssociatedObject(base: self, key: &MotionTransitionItemControllerKey) {
return MotionTransitionItemController(delegate: MotionTransitionDelegate())
}
}
set(value) {
AssociateObject(base: self, key: &MotionTransitionItemControllerKey, value: value)
}
}
open var transitionDelegate: MotionTransitionDelegate {
return motionTransition.delegate
}
}
extension UIView { extension UIView {
/// MaterialLayer Reference. /// MaterialLayer Reference.
fileprivate var motionTransitionItem: MotionTransitionItem { fileprivate var motionTransition: MotionTransitionItem {
get { get {
return AssociatedObject(base: self, key: &MotionIdentifierKey) { return AssociatedObject(base: self, key: &MotionTransitionItemKey) {
return MotionTransitionItem(identifier: "", animations: []) return MotionTransitionItem(identifier: "", animations: [])
} }
} }
set(value) { set(value) {
AssociateObject(base: self, key: &MotionIdentifierKey, value: value) AssociateObject(base: self, key: &MotionTransitionItemKey, value: value)
} }
} }
open var motionIdentifier: String { open var transitionIdentifier: String {
get { get {
return motionTransitionItem.identifier return motionTransition.identifier
} }
set(value) { set(value) {
motionTransitionItem.identifier = value motionTransition.identifier = value
} }
} }
open var motionAnimations: [MotionAnimation] { open var transitionAnimations: [MotionAnimation] {
get { get {
return motionTransitionItem.animations return motionTransition.animations
} }
set(value) { set(value) {
motionTransitionItem.animations = value motionTransition.animations = value
} }
} }
} }
@objc(MotionTransition) open class MotionTransitionAnimator: NSObject, UIViewControllerAnimatedTransitioning {
public enum MotionTransition: Int { public func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
case none
case fade }
public func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
return 0.25
}
}
open class MotionTransitionInteractiveAnimator: NSObject, UIViewControllerInteractiveTransitioning {
public func startInteractiveTransition(_ transitionContext: UIViewControllerContextTransitioning) {
}
} }
open class MotionTransitionDelegate: NSObject, UIViewControllerTransitioningDelegate { open class MotionTransitionDelegate: NSObject {
open var isPresenting = false
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 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 {
return
}
guard let fVC = transitionContext.viewController(forKey: .from) else {
return
}
let 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)
}
open func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
return 0.25
}
}
extension MotionTransitionDelegate: UIViewControllerTransitioningDelegate {
open func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? { open func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return nil return MotionTransitionAnimator()
} }
open func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? { open func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return nil return MotionTransitionAnimator()
} }
open func interactionControllerForDismissal(using animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? { open func interactionControllerForDismissal(using animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
return nil return MotionTransitionInteractiveAnimator()
} }
open func interactionControllerForPresentation(using animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? { open func interactionControllerForPresentation(using animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
return nil return MotionTransitionInteractiveAnimator()
}
}
extension MotionTransitionDelegate: UINavigationControllerDelegate {
open func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationControllerOperation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
isPresenting = operation == .push
return MotionTransitionAnimator()
}
open func navigationController(_ navigationController: UINavigationController, interactionControllerFor animationController: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
return MotionTransitionInteractiveAnimator()
}
}
extension MotionTransitionDelegate: UITabBarControllerDelegate {
// open func tabBarController(_ tabBarController: UITabBarController, interactionControllerFor animationController: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
// return MotionTransitionAnimator()
// }
open func tabBarController(_ tabBarController: UITabBarController, animationControllerForTransitionFrom fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
isPresenting = true
self.fromViewController = fromViewController ?? fromVC
self.toViewController = toViewController ?? toVC
// self.inContainerController = true
return MotionTransitionAnimator()
} }
} }
...@@ -110,9 +219,9 @@ open class FadeMotionTransition: NSObject, UIViewControllerAnimatedTransitioning ...@@ -110,9 +219,9 @@ open class FadeMotionTransition: NSObject, UIViewControllerAnimatedTransitioning
transitionContext.containerView.addSubview(toView) transitionContext.containerView.addSubview(toView)
UIView.animate(withDuration: transitionDuration(using: transitionContext), UIView.animate(withDuration: transitionDuration(using: transitionContext),
animations: { _ in animations: { _ in
toView.alpha = 1 toView.alpha = 1
fromView.alpha = 0 fromView.alpha = 0
}) { _ in }) { _ in
transitionContext.completeTransition(!transitionContext.transitionWasCancelled) transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
} }
...@@ -123,7 +232,7 @@ open class FadeMotionTransition: NSObject, UIViewControllerAnimatedTransitioning ...@@ -123,7 +232,7 @@ open class FadeMotionTransition: NSObject, UIViewControllerAnimatedTransitioning
} }
open func animationEnded(_ transitionCompleted: Bool) { open func animationEnded(_ transitionCompleted: Bool) {
print("FadeMotionTransition ANIMATION ENDED") print("FadeMotionTransition ANIMATION ENDED")
} }
} }
...@@ -143,43 +252,53 @@ open class SlideMotionTransition: NSObject, UIViewControllerAnimatedTransitionin ...@@ -143,43 +252,53 @@ open class SlideMotionTransition: NSObject, UIViewControllerAnimatedTransitionin
return return
} }
let duration = transitionDuration(using: nil) var duration = transitionDuration(using: nil)
if operation == .push {
switch operation { transitionContext.containerView.addSubview(toView)
case .push:
for n in fromView.subviews { for v in toView.subviews {
if 0 < n.motionIdentifier.utf16.count { if 0 < v.transitionIdentifier.utf16.count {
for m in toView.subviews { for a in v.transitionAnimations {
if n.motionIdentifier == m.motionIdentifier { switch a {
m.motion(m.motionAnimations) case let .duration(dur):
if dur > duration {
duration = dur
}
default:break
} }
} }
v.motion(v.transitionAnimations)
} }
} }
Motion.delay(time: duration) { Motion.delay(duration) {
transitionContext.completeTransition(!transitionContext.transitionWasCancelled) transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
} }
}
if operation == .pop {
transitionContext.containerView.addSubview(fromView)
transitionContext.containerView.addSubview(toView) for v in fromView.subviews {
case .pop: if 0 < v.transitionIdentifier.utf16.count {
for n in fromView.subviews { for a in v.transitionAnimations {
if 0 < n.motionIdentifier.utf16.count { switch a {
for m in toView.subviews { case let .duration(dur):
if n.motionIdentifier == m.motionIdentifier { if dur > duration {
m.motion(m.motionAnimations) duration = dur
}
default:break
} }
} }
v.motion(v.transitionAnimations)
} }
} }
Motion.delay(time: duration) { Motion.delay(duration) {
transitionContext.containerView.addSubview(toView)
transitionContext.completeTransition(!transitionContext.transitionWasCancelled) transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
} }
transitionContext.containerView.addSubview(toView)
case .none:break
} }
} }
...@@ -192,6 +311,84 @@ open class SlideMotionTransition: NSObject, UIViewControllerAnimatedTransitionin ...@@ -192,6 +311,84 @@ open class SlideMotionTransition: NSObject, UIViewControllerAnimatedTransitionin
} }
} }
//open class MotionTransitionAnimator: NSObject, UIViewControllerAnimatedTransitioning {
// var presenting = false
//
// open func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
// let containerView = transitionContext.containerView
//
// guard let fromVC = transitionContext.viewController(forKey: .from) else {
// return
// }
//
// guard let toVC = transitionContext.viewController(forKey: .to) else {
// return
// }
//
// guard let fromView = transitionContext.view(forKey: .from) else {
// return
// }
//
// guard let toView = transitionContext.view(forKey: .to) else {
// return
// }
//
// let containerFrame = containerView.frame
// var toViewStartFrame = transitionContext.initialFrame(for: toVC)
// let toViewFinalFrame = transitionContext.finalFrame(for: toVC)
// var fromViewFinalFrame = transitionContext.finalFrame(for: fromVC)
//
// // Set up the animation parameters.
// if (presenting) {
// // Modify the frame of the presented view so that it starts
// // offscreen at the lower-right corner of the container.
// toViewStartFrame.origin.x = containerFrame.size.width;
// toViewStartFrame.origin.y = containerFrame.size.height;
// }
// else {
// // Modify the frame of the dismissed view so it ends in
// // the lower-right corner of the container view.
// fromViewFinalFrame = CGRect(x: containerFrame.size.width,
// y: containerFrame.size.height,
// width: toView.frame.size.width,
// height: toView.frame.size.height);
// }
//
// // Always add the "to" view to the container.
// // And it doesn't hurt to set its start frame.
// containerView.addSubview(toView)
// toView.frame = toViewStartFrame;
//
// UIView.animate(withDuration: transitionDuration(using: nil), animations: { [weak self] in
// guard let s = self else {
// return
// }
//
// if s.presenting {
// toView.frame = toViewFinalFrame
// } else {
// fromView.frame = fromViewFinalFrame
// }
//
// }, completion: { [weak self] _ in
// guard let s = self else {
// return
// }
//
// let success = !transitionContext.transitionWasCancelled
// if (s.presenting && !success) || (!s.presenting && success) {
// toView.removeFromSuperview()
// }
//
// transitionContext.completeTransition(success)
// })
// }
//
// open func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
// return 0.25
// }
//}
//@objc(TransitionMotion) //@objc(TransitionMotion)
//public enum TransitionMotion: Int { //public enum TransitionMotion: Int {
......
...@@ -121,7 +121,7 @@ open class NavigationController: UINavigationController { ...@@ -121,7 +121,7 @@ open class NavigationController: UINavigationController {
open func prepare() { open func prepare() {
navigationBar.heightPreset = .normal navigationBar.heightPreset = .normal
navigationBar.width = view.width navigationBar.width = view.width
delegate = self delegate = transitionDelegate
view.clipsToBounds = true view.clipsToBounds = true
view.backgroundColor = .white view.backgroundColor = .white
view.contentScaleFactor = Screen.scale view.contentScaleFactor = Screen.scale
...@@ -134,12 +134,6 @@ open class NavigationController: UINavigationController { ...@@ -134,12 +134,6 @@ open class NavigationController: UINavigationController {
} }
} }
extension NavigationController: UINavigationControllerDelegate {
open func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationControllerOperation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return SlideMotionTransition(operation: operation)
}
}
extension NavigationController: UINavigationBarDelegate { extension NavigationController: UINavigationBarDelegate {
/** /**
Delegation method that is called when a new UINavigationItem is about to be pushed. Delegation method that is called when a new UINavigationItem is about to be pushed.
......
...@@ -156,7 +156,7 @@ extension PulseMotion { ...@@ -156,7 +156,7 @@ extension PulseMotion {
default:break default:break
} }
Motion.delay(time: duration) { Motion.delay(duration) {
bLayer.setValue(true, forKey: "animated") bLayer.setValue(true, forKey: "animated")
} }
} }
...@@ -173,7 +173,7 @@ extension PulseMotion { ...@@ -173,7 +173,7 @@ extension PulseMotion {
return return
} }
Motion.delay(time: animated ? 0 : 0.15) { [animation = animation, color = color] in Motion.delay(animated ? 0 : 0.15) { [animation = animation, color = color] in
guard let pLayer = bLayer.sublayers?.first as? CAShapeLayer else { guard let pLayer = bLayer.sublayers?.first as? CAShapeLayer else {
return return
} }
...@@ -192,7 +192,7 @@ extension PulseMotion { ...@@ -192,7 +192,7 @@ extension PulseMotion {
default:break default:break
} }
Motion.delay(time: duration) { Motion.delay(duration) {
pLayer.removeFromSuperlayer() pLayer.removeFromSuperlayer()
bLayer.removeFromSuperlayer() bLayer.removeFromSuperlayer()
} }
......
...@@ -75,7 +75,7 @@ open class PulseView: View, Pulseable { ...@@ -75,7 +75,7 @@ open class PulseView: View, Pulseable {
let p = point ?? center let p = point ?? center
pulse.expand(point: p) pulse.expand(point: p)
Motion.delay(time: 0.35) { [weak self] in Motion.delay(0.35) { [weak self] in
self?.pulse.contract() self?.pulse.contract()
} }
} }
......
...@@ -123,7 +123,7 @@ open class SnackbarController: RootController { ...@@ -123,7 +123,7 @@ open class SnackbarController: RootController {
*/ */
@discardableResult @discardableResult
open func animate(snackbar status: SnackbarStatus, delay: TimeInterval = 0, animations: ((Snackbar) -> Void)? = nil, completion: ((Snackbar) -> Void)? = nil) -> MotionDelayCancelBlock? { open func animate(snackbar status: SnackbarStatus, delay: TimeInterval = 0, animations: ((Snackbar) -> Void)? = nil, completion: ((Snackbar) -> Void)? = nil) -> MotionDelayCancelBlock? {
return Motion.delay(time: delay) { [weak self, status = status, animations = animations, completion = completion] in return Motion.delay(delay) { [weak self, status = status, animations = animations, completion = completion] in
guard let s = self else { guard let s = self else {
return return
} }
......
...@@ -117,7 +117,7 @@ open class TableViewCell: UITableViewCell, Pulseable { ...@@ -117,7 +117,7 @@ open class TableViewCell: UITableViewCell, Pulseable {
let p = point ?? center let p = point ?? center
pulse.expand(point: p) pulse.expand(point: p)
Motion.delay(time: 0.35) { [weak self] in Motion.delay(0.35) { [weak self] in
self?.pulse.contract() self?.pulse.contract()
} }
} }
......
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