Commit c7200fdf by Daniel Dahan

development: removed interactive MotionTransitions for initial release

parent ac027518
......@@ -30,7 +30,7 @@
import UIKit
open class BottomNavigationController: UITabBarController, UITabBarControllerDelegate {
open class BottomNavigationController: UITabBarController {
/**
An initializer that initializes the object with a NSCoder object.
- Parameter aDecoder: A NSCoder instance.
......@@ -110,15 +110,10 @@ open class BottomNavigationController: UITabBarController, UITabBarControllerDel
view.clipsToBounds = true
view.contentScaleFactor = Screen.scale
view.backgroundColor = .white
delegate = self
// delegate = self
prepareTabBar()
}
/// Handles transitions when tabBarItems are pressed.
open func tabBarController(_ tabBarController: UITabBarController, animationControllerForTransitionFrom fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return nil
}
/// Prepares the tabBar.
private func prepareTabBar() {
tabBar.heightPreset = .normal
......
......@@ -58,7 +58,7 @@ extension UIViewController {
}
}
open class CollectionViewController: MotionTransitionViewController {
open class CollectionViewController: UIViewController {
/// A reference to a Reminder.
open let collectionView = CollectionView()
......@@ -81,8 +81,7 @@ open class CollectionViewController: MotionTransitionViewController {
The super.prepareView method should always be called immediately
when subclassing.
*/
open override func prepare() {
super.prepare()
open func prepare() {
view.clipsToBounds = true
view.backgroundColor = .white
view.contentScaleFactor = Screen.scale
......
......@@ -280,7 +280,7 @@ extension CALayer {
a.append(Motion.translateY(to: to))
case let .translateZ(to):
a.append(Motion.translateZ(to: to))
case let .x(_), .y(_), .point(_, _):
case .x(_), .y(_), .point(_, _):
let position = Motion.position(to: CGPoint(x: px, y: py))
a.append(position)
case let .position(x, y):
......@@ -295,7 +295,7 @@ extension CALayer {
let zPosition = Motion.zPosition(index: index)
zPosition.fromValue = s.value(forKey: MotionAnimationKeyPath.zPosition.rawValue) ?? NSNumber(integerLiteral: 0)
a.append(zPosition)
case let .width(_), .height(_), .size(_, _):
case .width(_), .height(_), .size(_, _):
a.append(Motion.size(CGSize(width: w, height: h)))
default:break
}
......
......@@ -39,15 +39,15 @@ fileprivate struct MotionTransitionInstance {
}
fileprivate struct MotionTransitionInstanceController {
fileprivate var delegate: MotionTransition
fileprivate var isEnabled: Bool
}
extension UIViewController {
extension UIViewController: UIViewControllerTransitioningDelegate {
/// MotionTransitionInstanceController Reference.
fileprivate var motionTransition: MotionTransitionInstanceController {
get {
return AssociatedObject(base: self, key: &MotionTransitionInstanceControllerKey) {
return MotionTransitionInstanceController(delegate: MotionTransition())
return MotionTransitionInstanceController(isEnabled: false)
}
}
set(value) {
......@@ -55,40 +55,47 @@ extension UIViewController {
}
}
open var transitionDelegate: MotionTransition {
return motionTransition.delegate
open var isMotionTransitionEnabled: Bool {
get {
return motionTransition.isEnabled
}
set(value) {
if value {
modalPresentationStyle = .custom
transitioningDelegate = self
}
}
open class MotionTransitionViewController: UIViewController {
public init() {
super.init(nibName: nil, bundle: nil)
prepare()
motionTransition.isEnabled = value
}
}
}
public required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
prepare()
extension UIViewController {
open func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return isMotionTransitionEnabled ? MotionTransition(isPresenting: true) : nil
}
public override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
prepare()
open func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return isMotionTransitionEnabled ? MotionTransition() : nil
}
/**
Prepares the view instance when intialized. When subclassing,
it is recommended to override the prepare method
to initialize property values and other setup operations.
The super.prepare method should always be called immediately
when subclassing.
*/
open func prepare() {
modalPresentationStyle = .custom
transitioningDelegate = transitionDelegate
open func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? {
return isMotionTransitionEnabled ? MotionTransitionPresentationController(presentedViewController: presented, presenting: presenting) : nil
}
}
//extension UIViewController {
// open func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationControllerOperation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
// return isMotionTransitionEnabled ? MotionTransition(isPresenting: operation == .push) : nil
// }
//}
//
//extension UIViewController {
// open func tabBarController(_ tabBarController: UITabBarController, animationControllerForTransitionFrom fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
// return isMotionTransitionEnabled ? MotionTransition() : nil
// }
//}
extension UIView {
/// The global position of a view.
open var motionPosition: CGPoint {
......@@ -125,7 +132,7 @@ extension UIView {
}
}
open func snapshot(afterUpdates: Bool) -> UIView {
open func motionTransitionSnapshot(afterUpdates: Bool) -> UIView {
isHidden = false
(self as? Pulseable)?.pulse.pulseLayer?.isHidden = true
......@@ -212,9 +219,9 @@ open class MotionTransitionPresentationController: UIPresentationController {
open class MotionTransition: NSObject {
open var isPresenting: Bool
open var screenSnapshot: UIView!
open var transitionSnapshot: UIView!
open let backgroundView = UIView()
open let transitionBackgroundView = UIView()
open var toViewController: UIViewController!
......@@ -233,14 +240,17 @@ open class MotionTransition: NSObject {
super.init()
}
public init(isPresenting: Bool) {
self.isPresenting = isPresenting
super.init()
}
open var toView: UIView {
return toViewController.view
}
open var toSubviews: [UIView] {
var views: [UIView] = []
subviews(of: toView, views: &views)
return views
return subviews(of: toView)
}
open var fromView: UIView {
......@@ -248,8 +258,12 @@ open class MotionTransition: NSObject {
}
open var fromSubviews: [UIView] {
return subviews(of: fromView)
}
open func subviews(of view: UIView) -> [UIView] {
var views: [UIView] = []
subviews(of: fromView, views: &views)
subviews(of: view, views: &views)
return views
}
......@@ -263,91 +277,64 @@ open class MotionTransition: NSObject {
}
}
extension MotionTransition: UIViewControllerTransitioningDelegate {
open func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return MotionTransitionPresentedAnimator()
}
open func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return MotionTransitionDismissedAnimator()
}
open func interactionControllerForDismissal(using animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
return nil // MotionTransitionInteractiveAnimator()
}
open func interactionControllerForPresentation(using animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
return nil // MotionTransitionInteractiveAnimator()
}
public func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? {
return MotionTransitionPresentationController(presentedViewController: presented, presenting: presenting)
}
}
extension MotionTransition: UIViewControllerAnimatedTransitioning {
@objc(animateTransition:)
open func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
self.transitionContext = transitionContext
extension MotionTransition: UINavigationControllerDelegate {
open func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationControllerOperation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
isPresenting = operation == .push
return self
prepareToViewController()
prepareFromViewController()
prepareContainerView()
prepareTransitionView()
prepareTransitionBackgroundView()
prepareTransitionSnapshot()
prepareToView()
prepareTransitionAnimation()
}
open func navigationController(_ navigationController: UINavigationController, interactionControllerFor animationController: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
return MotionTransitionInteractiveAnimator()
@objc(transitionDuration:)
open func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
return delay + duration
}
}
extension MotionTransition: UITabBarControllerDelegate {
open func tabBarController(_ tabBarController: UITabBarController, animationControllerForTransitionFrom fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
isPresenting = true
self.fromViewController = fromViewController ?? fromVC
self.toViewController = toViewController ?? toVC
return self
extension MotionTransition {
fileprivate func prepareToViewController() {
guard let v = transitionContext.viewController(forKey: .to) else {
return
}
open func tabBarController(_ tabBarController: UITabBarController, interactionControllerFor animationController: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
return MotionTransitionInteractiveAnimator()
toViewController = v
}
}
extension MotionTransition: UIViewControllerAnimatedTransitioning {
@objc(animateTransition:)
open func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
guard let tVC = transitionContext.viewController(forKey: .to) else {
fileprivate func prepareFromViewController() {
guard let v = transitionContext.viewController(forKey: .from) else {
return
}
guard let fVC = transitionContext.viewController(forKey: .from) else {
return
fromViewController = v
}
self.transitionContext = transitionContext
fileprivate func prepareContainerView() {
containerView = transitionContext.containerView
containerView.addSubview(transitionView)
transitionView.frame = containerView.bounds
toViewController = tVC
fromViewController = fVC
prepareAnimation()
}
@objc(transitionDuration:)
open func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
return delay + duration
fileprivate func prepareTransitionView() {
transitionView.frame = containerView.bounds
containerView.addSubview(transitionView)
}
}
extension MotionTransition {
fileprivate func prepareAnimation() {
screenSnapshot = fromView.snapshot(afterUpdates: true)
screenSnapshot.frame = containerView.bounds
containerView.addSubview(screenSnapshot)
fileprivate func prepareTransitionBackgroundView() {
transitionBackgroundView.backgroundColor = fromView.backgroundColor
transitionBackgroundView.frame = transitionView.bounds
transitionView.addSubview(transitionBackgroundView)
}
backgroundView.backgroundColor = fromView.backgroundColor
backgroundView.frame = transitionView.bounds
transitionView.addSubview(backgroundView)
fileprivate func prepareTransitionSnapshot() {
transitionSnapshot = fromView.motionTransitionSnapshot(afterUpdates: true)
transitionSnapshot.frame = containerView.bounds
transitionView.addSubview(transitionSnapshot)
}
fileprivate func prepareToView() {
if isPresenting {
containerView.insertSubview(toView, belowSubview: transitionView)
}
......@@ -356,14 +343,14 @@ extension MotionTransition {
toView.setNeedsLayout()
toView.layoutIfNeeded()
toView.isHidden = false
}
for tv in toSubviews {
fileprivate func prepareTransitionAnimation() {
for fv in fromSubviews {
for tv in toSubviews {
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 tv.motionTransitionAnimations {
......@@ -382,6 +369,9 @@ extension MotionTransition {
}
}
var snapshotAnimations = [CABasicAnimation]()
var snapshotChildAnimations = [CABasicAnimation]()
snapshotAnimations.append(Motion.position(to: tv.motionPosition))
let sizeAnimation = Motion.size(tv.bounds.size)
......@@ -398,8 +388,8 @@ extension MotionTransition {
snapshotAnimations.append(cornerRadiusAnimation)
snapshotChildAnimations.append(cornerRadiusAnimation)
let snapshot = fv.snapshot(afterUpdates: true)
transitionView.insertSubview(snapshot, belowSubview: screenSnapshot)
let snapshot = fv.motionTransitionSnapshot(afterUpdates: true)
transitionView.insertSubview(snapshot, belowSubview: transitionSnapshot)
Motion.delay(t) {
for ta in tv.motionTransitionAnimations {
......@@ -429,142 +419,59 @@ extension MotionTransition {
}
}
let d = transitionDuration(using: transitionContext)
if isPresenting, let v = backgroundView.backgroundColor {
backgroundView.motion(.backgroundColor(v), .duration(d))
} else if nil != backgroundView.backgroundColor {
backgroundView.motion(.backgroundColor(.clear), .duration(d))
}
Motion.delay(d) { [weak self] in
guard let s = self else {
return
}
addBackgroundMotionAnimation()
defer {
s.transitionContext.completeTransition(!s.transitionContext.transitionWasCancelled)
cleanupAnimation()
cleanupFromView()
cleanupTransitionSnapshot()
}
}
for v in s.toSubviews {
v.isHidden = false
extension MotionTransition {
fileprivate func addBackgroundMotionAnimation() {
transitionBackgroundView.motion(.backgroundColor(toView.backgroundColor ?? .clear), .duration(transitionDuration(using: transitionContext)))
}
}
s.transitionView.removeFromSuperview()
for v in s.transitionView.subviews {
v.removeFromSuperview()
}
extension MotionTransition {
fileprivate func cleanupAnimation() {
Motion.delay(transitionDuration(using: transitionContext)) { [weak self] in
guard let s = self else {
return
}
fromView.isHidden = true
screenSnapshot.removeFromSuperview()
s.hideToSubviews()
s.clearTransitionView()
s.completeTransition()
}
}
open class MotionTransitionPresentedAnimator: MotionTransition {
public override init() {
super.init()
isPresenting = true
}
}
open class MotionTransitionDismissedAnimator: MotionTransition {}
open class MotionTransitionInteractiveAnimator: MotionTransitionInteractiveDelegate {
open override func startInteractiveTransition(_ transitionContext: UIViewControllerContextTransitioning) {
super.startInteractiveTransition(transitionContext)
fileprivate func cleanupFromView() {
Motion.delay(delay) { [weak self] in
self?.fromView.isHidden = true
}
}
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
fileprivate func cleanupTransitionSnapshot() {
Motion.delay(delay) { [weak self] in
self?.transitionSnapshot.removeFromSuperview()
}
guard let fView = transitionContext.view(forKey: .from) else {
return
}
guard let fVC = transitionContext.viewController(forKey: .from) else {
return
fileprivate func hideToSubviews() {
toSubviews.forEach {
$0.isHidden = false
}
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)
fileprivate func clearTransitionView() {
transitionView.removeFromSuperview()
transitionView.subviews.forEach {
$0.removeFromSuperview()
}
}
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
}
fileprivate func completeTransition() {
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
}
}
......@@ -121,7 +121,7 @@ open class NavigationController: UINavigationController {
open func prepare() {
navigationBar.heightPreset = .normal
navigationBar.width = view.width
delegate = transitionDelegate
// delegate = self
view.clipsToBounds = true
view.backgroundColor = .white
view.contentScaleFactor = Screen.scale
......
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