Commit 83ff4857 by Daniel Dahan

development: simplified MotionTransition logic

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