Commit 83ff4857 by Daniel Dahan

development: simplified MotionTransition logic

parent 5ee12903
...@@ -30,32 +30,32 @@ ...@@ -30,32 +30,32 @@
import UIKit import UIKit
fileprivate var MotionTransitionItemKey: UInt8 = 0 fileprivate var MotionTransitionInstanceKey: UInt8 = 0
fileprivate var MotionTransitionItemControllerKey: UInt8 = 0 fileprivate var MotionTransitionInstanceControllerKey: UInt8 = 0
fileprivate struct MotionTransitionItem { fileprivate struct MotionTransitionInstance {
fileprivate var identifier: String fileprivate var identifier: String
fileprivate var animations: [MotionAnimation] fileprivate var animations: [MotionAnimation]
} }
fileprivate struct MotionTransitionItemController { fileprivate struct MotionTransitionInstanceController {
fileprivate var delegate: MotionTransitionAnimator fileprivate var delegate: MotionTransition
} }
extension UIViewController { extension UIViewController {
/// MaterialLayer Reference. /// MotionTransitionInstanceController Reference.
fileprivate var motionTransition: MotionTransitionItemController { fileprivate var motionTransition: MotionTransitionInstanceController {
get { get {
return AssociatedObject(base: self, key: &MotionTransitionItemControllerKey) { return AssociatedObject(base: self, key: &MotionTransitionInstanceControllerKey) {
return MotionTransitionItemController(delegate: MotionTransitionAnimator()) return MotionTransitionInstanceController(delegate: MotionTransition())
} }
} }
set(value) { set(value) {
AssociateObject(base: self, key: &MotionTransitionItemControllerKey, value: value) AssociateObject(base: self, key: &MotionTransitionInstanceControllerKey, value: value)
} }
} }
open var transitionDelegate: MotionTransitionAnimator { open var transitionDelegate: MotionTransition {
return motionTransition.delegate return motionTransition.delegate
} }
} }
...@@ -90,15 +90,20 @@ open class MotionTransitionViewController: UIViewController { ...@@ -90,15 +90,20 @@ open class MotionTransitionViewController: UIViewController {
} }
extension UIView { extension UIView {
/// MaterialLayer Reference. /// The global position of a view.
fileprivate var motionTransition: MotionTransitionItem { open var motionPosition: CGPoint {
return superview?.convert(position, to: nil) ?? position
}
/// MaterialTransitionItem Reference.
fileprivate var motionTransition: MotionTransitionInstance {
get { get {
return AssociatedObject(base: self, key: &MotionTransitionItemKey) { return AssociatedObject(base: self, key: &MotionTransitionInstanceKey) {
return MotionTransitionItem(identifier: "", animations: []) return MotionTransitionInstance(identifier: "", animations: [])
} }
} }
set(value) { set(value) {
AssociateObject(base: self, key: &MotionTransitionItemKey, value: value) AssociateObject(base: self, key: &MotionTransitionInstanceKey, value: value)
} }
} }
...@@ -120,44 +125,42 @@ extension UIView { ...@@ -120,44 +125,42 @@ extension UIView {
} }
} }
open func snapshot(view: UIView, afterUpdates: Bool) -> UIView { open func snapshot(afterUpdates: Bool) -> UIView {
view.isHidden = false isHidden = false
(view as? Pulseable)?.pulse.pulseLayer?.isHidden = true (self as? Pulseable)?.pulse.pulseLayer?.isHidden = true
let oldCornerRadius = view.cornerRadius let oldCornerRadius = cornerRadius
view.cornerRadius = 0 cornerRadius = 0
let v = view.snapshotView(afterScreenUpdates: afterUpdates)! let v = snapshotView(afterScreenUpdates: afterUpdates)!
view.cornerRadius = oldCornerRadius cornerRadius = oldCornerRadius
let contentView = v.subviews.first! let contentView = v.subviews.first!
contentView.cornerRadius = view.cornerRadius contentView.cornerRadius = cornerRadius
contentView.masksToBounds = true contentView.masksToBounds = true
v.motionTransitionIdentifier = view.motionTransitionIdentifier v.motionTransitionIdentifier = motionTransitionIdentifier
v.position = view.superview?.convert(view.position, to: nil) ?? view.position v.position = motionPosition
v.bounds = view.bounds v.bounds = bounds
v.cornerRadius = view.cornerRadius v.cornerRadius = cornerRadius
v.zPosition = view.zPosition v.zPosition = zPosition
v.opacity = view.opacity v.opacity = opacity
v.isOpaque = view.isOpaque v.isOpaque = isOpaque
v.anchorPoint = view.anchorPoint v.anchorPoint = anchorPoint
v.masksToBounds = view.masksToBounds v.masksToBounds = masksToBounds
v.backgroundColor = view.backgroundColor v.backgroundColor = backgroundColor
v.borderColor = view.borderColor v.borderColor = borderColor
v.borderWidth = view.borderWidth v.borderWidth = borderWidth
v.shadowRadius = view.shadowRadius v.shadowRadius = shadowRadius
v.shadowOpacity = view.shadowOpacity v.shadowOpacity = shadowOpacity
v.shadowColor = view.shadowColor v.shadowColor = shadowColor
v.shadowOffset = view.shadowOffset v.shadowOffset = shadowOffset
v.contentMode = view.contentMode v.contentMode = contentMode
v.layer.transform = view.layer.transform v.layer.transform = layer.transform
view.isHidden = true isHidden = true
(view as? Pulseable)?.pulse.pulseLayer?.isHidden = false (self as? Pulseable)?.pulse.pulseLayer?.isHidden = false
addSubview(v)
return v return v
} }
...@@ -201,7 +204,7 @@ open class MotionTransitionPresentationController: UIPresentationController { ...@@ -201,7 +204,7 @@ open class MotionTransitionPresentationController: UIPresentationController {
} }
} }
open class MotionTransitionAnimator: NSObject { open class MotionTransition: NSObject {
open var isPresenting = false open var isPresenting = false
open var toViewController: UIViewController! open var toViewController: UIViewController!
...@@ -216,20 +219,37 @@ open class MotionTransitionAnimator: NSObject { ...@@ -216,20 +219,37 @@ open class MotionTransitionAnimator: NSObject {
open var containerView: UIView! open var containerView: UIView!
open var transitionView = UIView() open var transitionView = UIView()
public var toViews: [UIView] { open var toView: UIView {
return toViewController.view
}
open var toSubviews: [UIView] {
var views: [UIView] = [] var views: [UIView] = []
subviews(of: toViewController.view, views: &views) subviews(of: toView, views: &views)
return views return views
} }
public var fromViews: [UIView] { open var fromView: UIView {
return fromViewController.view
}
open var fromSubviews: [UIView] {
var views: [UIView] = [] var views: [UIView] = []
subviews(of: fromViewController.view, views: &views) subviews(of: fromView, views: &views)
return views return views
} }
open 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 MotionTransitionAnimator: UIViewControllerTransitioningDelegate { extension MotionTransition: UIViewControllerTransitioningDelegate {
open func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? { open func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return MotionTransitionPresentedAnimator() return MotionTransitionPresentedAnimator()
} }
...@@ -251,7 +271,7 @@ extension MotionTransitionAnimator: UIViewControllerTransitioningDelegate { ...@@ -251,7 +271,7 @@ extension MotionTransitionAnimator: UIViewControllerTransitioningDelegate {
} }
} }
extension MotionTransitionAnimator: UINavigationControllerDelegate { extension MotionTransition: UINavigationControllerDelegate {
open func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationControllerOperation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? { open func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationControllerOperation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
isPresenting = operation == .push isPresenting = operation == .push
return self return self
...@@ -262,7 +282,7 @@ extension MotionTransitionAnimator: UINavigationControllerDelegate { ...@@ -262,7 +282,7 @@ extension MotionTransitionAnimator: UINavigationControllerDelegate {
} }
} }
extension MotionTransitionAnimator: UITabBarControllerDelegate { extension MotionTransition: UITabBarControllerDelegate {
open func tabBarController(_ tabBarController: UITabBarController, animationControllerForTransitionFrom fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? { open func tabBarController(_ tabBarController: UITabBarController, animationControllerForTransitionFrom fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
isPresenting = true isPresenting = true
self.fromViewController = fromViewController ?? fromVC self.fromViewController = fromViewController ?? fromVC
...@@ -276,7 +296,7 @@ extension MotionTransitionAnimator: UITabBarControllerDelegate { ...@@ -276,7 +296,7 @@ extension MotionTransitionAnimator: UITabBarControllerDelegate {
} }
} }
extension MotionTransitionAnimator: UIViewControllerAnimatedTransitioning { extension MotionTransition: UIViewControllerAnimatedTransitioning {
@objc(animateTransition:) @objc(animateTransition:)
open func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { open func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
guard let tVC = transitionContext.viewController(forKey: .to) else { guard let tVC = transitionContext.viewController(forKey: .to) else {
...@@ -303,44 +323,34 @@ extension MotionTransitionAnimator: UIViewControllerAnimatedTransitioning { ...@@ -303,44 +323,34 @@ extension MotionTransitionAnimator: UIViewControllerAnimatedTransitioning {
} }
} }
extension MotionTransitionAnimator { open class MotionTransitionPresentedAnimator: MotionTransition {
fileprivate func subviews(of view: UIView, views: inout [UIView]) { open let backgroundView = UIView()
for v in view.subviews {
if 0 < v.motionTransitionIdentifier.utf16.count {
views.append(v)
}
subviews(of: v, views: &views)
}
}
}
open class MotionTransitionPresentedAnimator: MotionTransitionAnimator {
@objc(animateTransition:) @objc(animateTransition:)
open override func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { open override func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
super.animateTransition(using: transitionContext) super.animateTransition(using: transitionContext)
transitionView.isHidden = true transitionView.isHidden = true
let bgView = UIView() backgroundView.backgroundColor = fromView.backgroundColor
bgView.backgroundColor = fromViewController.view.backgroundColor backgroundView.frame = transitionView.bounds
bgView.frame = transitionView.bounds transitionView.addSubview(backgroundView)
transitionView.addSubview(bgView)
containerView.insertSubview(toViewController.view, belowSubview: transitionView) containerView.insertSubview(toView, belowSubview: transitionView)
toViewController.view.updateConstraints() toView.updateConstraints()
toViewController.view.setNeedsLayout() toView.setNeedsLayout()
toViewController.view.layoutIfNeeded() toView.layoutIfNeeded()
for toView in toViews { for tv in toSubviews {
for fromView in fromViews { for fv in fromSubviews {
if toView.motionTransitionIdentifier == fromView.motionTransitionIdentifier { if tv.motionTransitionIdentifier == fv.motionTransitionIdentifier {
var t: TimeInterval = 0 var t: TimeInterval = 0
var d: TimeInterval = 0 var d: TimeInterval = 0
var snapshotAnimations = [CABasicAnimation]() var snapshotAnimations = [CABasicAnimation]()
var snapshotChildAnimations = [CABasicAnimation]() var snapshotChildAnimations = [CABasicAnimation]()
var tf = MotionAnimationTimingFunction.easeInEaseOut var tf = MotionAnimationTimingFunction.easeInEaseOut
for ta in toView.motionTransitionAnimations { for ta in tv.motionTransitionAnimations {
switch ta { switch ta {
case let .delay(time): case let .delay(time):
if time > delay { if time > delay {
...@@ -356,28 +366,25 @@ open class MotionTransitionPresentedAnimator: MotionTransitionAnimator { ...@@ -356,28 +366,25 @@ open class MotionTransitionPresentedAnimator: MotionTransitionAnimator {
} }
} }
let b = toView.bounds snapshotAnimations.append(Motion.position(to: tv.motionPosition))
let w = b.width
let h = b.height
let p = toView.superview?.convert(toView.position, to: nil) ?? toView.position
snapshotAnimations.append(Motion.position(x: p.x, y: p.y))
let sizeAnimation = Motion.size(CGSize(width: w, height: h)) let sizeAnimation = Motion.size(tv.bounds.size)
snapshotAnimations.append(sizeAnimation) snapshotAnimations.append(sizeAnimation)
snapshotChildAnimations.append(Motion.position(x: w / 2, y: h / 2))
snapshotChildAnimations.append(sizeAnimation) snapshotChildAnimations.append(sizeAnimation)
snapshotAnimations.append(Motion.rotate(angle: toView.motionRotationAngle)) snapshotChildAnimations.append(Motion.position(x: tv.bounds.width / 2, y: tv.bounds.height / 2))
let cornerRadiusAnimation = Motion.corner(radius: toView.cornerRadius) snapshotAnimations.append(Motion.rotate(angle: tv.motionRotationAngle))
let cornerRadiusAnimation = Motion.corner(radius: tv.cornerRadius)
snapshotAnimations.append(cornerRadiusAnimation) snapshotAnimations.append(cornerRadiusAnimation)
snapshotChildAnimations.append(cornerRadiusAnimation) snapshotChildAnimations.append(cornerRadiusAnimation)
let snapshot = transitionView.snapshot(view: fromView, afterUpdates: true) let snapshot = fv.snapshot(afterUpdates: true)
transitionView.addSubview(snapshot)
Motion.delay(t) { Motion.delay(t) {
for ta in toView.motionTransitionAnimations { for ta in tv.motionTransitionAnimations {
switch ta { switch ta {
case let .timingFunction(timingFunction): case let .timingFunction(timingFunction):
tf = timingFunction tf = timingFunction
...@@ -406,8 +413,8 @@ open class MotionTransitionPresentedAnimator: MotionTransitionAnimator { ...@@ -406,8 +413,8 @@ open class MotionTransitionPresentedAnimator: MotionTransitionAnimator {
let d = transitionDuration(using: transitionContext) let d = transitionDuration(using: transitionContext)
if let v = toViewController.view.backgroundColor { if let v = toView.backgroundColor {
bgView.motion(.backgroundColor(v), .duration(d)) backgroundView.motion(.backgroundColor(v), .duration(d))
} }
Motion.delay(d) { [weak self] in Motion.delay(d) { [weak self] in
...@@ -429,7 +436,7 @@ open class MotionTransitionPresentedAnimator: MotionTransitionAnimator { ...@@ -429,7 +436,7 @@ open class MotionTransitionPresentedAnimator: MotionTransitionAnimator {
} }
} }
open class MotionTransitionDismissedAnimator: MotionTransitionAnimator { open class MotionTransitionDismissedAnimator: MotionTransition {
@objc(animateTransition:) @objc(animateTransition:)
open override func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { open override func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
super.animateTransition(using: transitionContext) super.animateTransition(using: transitionContext)
...@@ -437,24 +444,24 @@ open class MotionTransitionDismissedAnimator: MotionTransitionAnimator { ...@@ -437,24 +444,24 @@ open class MotionTransitionDismissedAnimator: MotionTransitionAnimator {
transitionView.isHidden = true transitionView.isHidden = true
let bgView = UIView() let bgView = UIView()
bgView.backgroundColor = fromViewController.view.backgroundColor bgView.backgroundColor = fromView.backgroundColor
bgView.frame = transitionView.bounds bgView.frame = transitionView.bounds
transitionView.addSubview(bgView) transitionView.addSubview(bgView)
toViewController.view.updateConstraints() toView.updateConstraints()
toViewController.view.setNeedsLayout() toView.setNeedsLayout()
toViewController.view.layoutIfNeeded() toView.layoutIfNeeded()
for toView in toViews { for tv in toSubviews {
for fromView in fromViews { for fv in fromSubviews {
if toView.motionTransitionIdentifier == fromView.motionTransitionIdentifier { if tv.motionTransitionIdentifier == fv.motionTransitionIdentifier {
var t: TimeInterval = 0 var t: TimeInterval = 0
var d: TimeInterval = 0 var d: TimeInterval = 0
var snapshotAnimations = [CABasicAnimation]() var snapshotAnimations = [CABasicAnimation]()
var snapshotChildAnimations = [CABasicAnimation]() var snapshotChildAnimations = [CABasicAnimation]()
var tf = MotionAnimationTimingFunction.easeInEaseOut var tf = MotionAnimationTimingFunction.easeInEaseOut
for ta in toView.motionTransitionAnimations { for ta in tv.motionTransitionAnimations {
switch ta { switch ta {
case let .delay(time): case let .delay(time):
if time > delay { if time > delay {
...@@ -470,28 +477,25 @@ open class MotionTransitionDismissedAnimator: MotionTransitionAnimator { ...@@ -470,28 +477,25 @@ open class MotionTransitionDismissedAnimator: MotionTransitionAnimator {
} }
} }
let b = toView.bounds snapshotAnimations.append(Motion.position(to: tv.motionPosition))
let w = b.width
let h = b.height
let p = toView.superview?.convert(toView.position, to: nil) ?? toView.position
snapshotAnimations.append(Motion.position(x: p.x, y: p.y))
let sizeAnimation = Motion.size(CGSize(width: w, height: h)) let sizeAnimation = Motion.size(tv.bounds.size)
snapshotAnimations.append(sizeAnimation) snapshotAnimations.append(sizeAnimation)
snapshotChildAnimations.append(Motion.position(x: w / 2, y: h / 2))
snapshotChildAnimations.append(sizeAnimation) snapshotChildAnimations.append(sizeAnimation)
snapshotAnimations.append(Motion.rotate(angle: toView.motionRotationAngle)) snapshotChildAnimations.append(Motion.position(x: tv.bounds.width / 2, y: tv.bounds.height / 2))
snapshotAnimations.append(Motion.rotate(angle: tv.motionRotationAngle))
let cornerRadiusAnimation = Motion.corner(radius: toView.cornerRadius) let cornerRadiusAnimation = Motion.corner(radius: tv.cornerRadius)
snapshotAnimations.append(cornerRadiusAnimation) snapshotAnimations.append(cornerRadiusAnimation)
snapshotChildAnimations.append(cornerRadiusAnimation) snapshotChildAnimations.append(cornerRadiusAnimation)
let snapshot = transitionView.snapshot(view: fromView, afterUpdates: true) let snapshot = fv.snapshot(afterUpdates: true)
transitionView.addSubview(snapshot)
Motion.delay(t) { Motion.delay(t) {
for ta in toView.motionTransitionAnimations { for ta in tv.motionTransitionAnimations {
switch ta { switch ta {
case let .timingFunction(timingFunction): case let .timingFunction(timingFunction):
tf = timingFunction tf = timingFunction
...@@ -518,7 +522,7 @@ open class MotionTransitionDismissedAnimator: MotionTransitionAnimator { ...@@ -518,7 +522,7 @@ open class MotionTransitionDismissedAnimator: MotionTransitionAnimator {
} }
} }
fromViewController.view.isHidden = true fromView.isHidden = true
let d = transitionDuration(using: transitionContext) let d = transitionDuration(using: transitionContext)
...@@ -535,7 +539,7 @@ open class MotionTransitionDismissedAnimator: MotionTransitionAnimator { ...@@ -535,7 +539,7 @@ open class MotionTransitionDismissedAnimator: MotionTransitionAnimator {
return return
} }
for v in s.toViews { for v in s.toSubviews {
v.isHidden = false v.isHidden = false
} }
......
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