Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
M
Motion
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Dmitriy Stepanets
Motion
Commits
baf1bf57
Unverified
Commit
baf1bf57
authored
Jun 06, 2017
by
Daniel Dahan
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
reworked Motion+UIViewController
parent
53088a53
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
330 additions
and
250 deletions
+330
-250
Motion.xcodeproj/project.pbxproj
+2
-2
Sources/Extensions/Motion+UIView.swift
+17
-17
Sources/Extensions/Motion+UIViewController.swift
+291
-211
Sources/Motion.swift
+6
-6
Sources/MotionController.swift
+14
-14
No files found.
Motion.xcodeproj/project.pbxproj
View file @
baf1bf57
...
...
@@ -53,7 +53,7 @@
/* Begin PBXFileReference section */
963150D11EE50DA6002B0D42
/* Motion+Obj-C.swift */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.swift
;
path
=
"Motion+Obj-C.swift"
;
sourceTree
=
"<group>"
;
};
963150D41EE51C7A002B0D42
/* MotionAnimation.swift */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.swift
;
path
=
MotionAnimation.swift
;
sourceTree
=
"<group>"
;
};
963150D91EE51EB4002B0D42
/* MotionAnimationFillMode.swift */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.swift
;
path
=
MotionAnimationFillMode.swift
;
sourceTree
=
"<group>"
;
};
963150D91EE51EB4002B0D42
/* MotionAnimationFillMode.swift */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.swift
;
name
=
MotionAnimationFillMode.swift
;
path
=
../Extensions/
MotionAnimationFillMode.swift
;
sourceTree
=
"<group>"
;
};
968989B81EE5B34B003B8F3D
/* MotionHasInsertOrder.swift */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.swift
;
path
=
MotionHasInsertOrder.swift
;
sourceTree
=
"<group>"
;
};
968989DB1EE65F2B003B8F3D
/* MotionPreprocessor.swift */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.swift
;
path
=
MotionPreprocessor.swift
;
sourceTree
=
"<group>"
;
};
968989DD1EE6633E003B8F3D
/* MotionAnimator.swift */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.swift
;
path
=
MotionAnimator.swift
;
sourceTree
=
"<group>"
;
};
...
...
@@ -117,6 +117,7 @@
96AEB6671EE4610F009A3BE0
/* MotionDefaultAnimator.swift */
,
96AEB6681EE4610F009A3BE0
/* MotionViewPropertyViewContext.swift */
,
968989B81EE5B34B003B8F3D
/* MotionHasInsertOrder.swift */
,
963150D91EE51EB4002B0D42
/* MotionAnimationFillMode.swift */
,
);
path
=
Animator
;
sourceTree
=
"<group>"
;
...
...
@@ -141,7 +142,6 @@
96AEB6731EE4610F009A3BE0
/* Motion+UIKit.swift */
,
96AEB6741EE4610F009A3BE0
/* Motion+UIView.swift */
,
96AEB6751EE4610F009A3BE0
/* Motion+UIViewController.swift */
,
963150D91EE51EB4002B0D42
/* MotionAnimationFillMode.swift */
,
);
path
=
Extensions
;
sourceTree
=
"<group>"
;
...
...
Sources/Extensions/Motion+UIView.swift
View file @
baf1bf57
...
...
@@ -49,9 +49,9 @@ internal extension UIView {
}
}
fileprivate
var
Motion
InstanceKey
:
UInt8
=
0
fileprivate
var
Associated
InstanceKey
:
UInt8
=
0
fileprivate
struct
Motion
Instance
{
fileprivate
struct
Associated
Instance
{
/// A boolean indicating whether Motion is enabled.
fileprivate
var
isEnabled
:
Bool
...
...
@@ -69,15 +69,15 @@ fileprivate struct MotionInstance {
}
extension
UIView
{
///
Motion
Instance reference.
fileprivate
var
motionInstance
:
Motion
Instance
{
///
Associated
Instance reference.
fileprivate
var
associatedInstance
:
Associated
Instance
{
get
{
return
AssociatedObject
.
get
(
base
:
self
,
key
:
&
Motion
InstanceKey
)
{
return
Motion
Instance
(
isEnabled
:
true
,
identifier
:
nil
,
animations
:
nil
,
transitions
:
nil
,
alpha
:
1
)
return
AssociatedObject
.
get
(
base
:
self
,
key
:
&
Associated
InstanceKey
)
{
return
Associated
Instance
(
isEnabled
:
true
,
identifier
:
nil
,
animations
:
nil
,
transitions
:
nil
,
alpha
:
1
)
}
}
set
(
value
)
{
AssociatedObject
.
set
(
base
:
self
,
key
:
&
Motion
InstanceKey
,
value
:
value
)
AssociatedObject
.
set
(
base
:
self
,
key
:
&
Associated
InstanceKey
,
value
:
value
)
}
}
...
...
@@ -85,10 +85,10 @@ extension UIView {
@IBInspectable
public
var
isMotionEnabled
:
Bool
{
get
{
return
motion
Instance
.
isEnabled
return
associated
Instance
.
isEnabled
}
set
(
value
)
{
motion
Instance
.
isEnabled
=
value
associated
Instance
.
isEnabled
=
value
}
}
...
...
@@ -96,30 +96,30 @@ extension UIView {
@IBInspectable
open
var
motionIdentifier
:
String
?
{
get
{
return
motion
Instance
.
identifier
return
associated
Instance
.
identifier
}
set
(
value
)
{
motion
Instance
.
identifier
=
value
associated
Instance
.
identifier
=
value
}
}
/// The animations to run.
open
var
motionAnimations
:
[
MotionAnimation
]?
{
get
{
return
motion
Instance
.
animations
return
associated
Instance
.
animations
}
set
(
value
)
{
motion
Instance
.
animations
=
value
associated
Instance
.
animations
=
value
}
}
/// The animations to run while in transition.
open
var
motionTransitions
:
[
MotionTransition
]?
{
get
{
return
motion
Instance
.
transitions
return
associated
Instance
.
transitions
}
set
(
value
)
{
motion
Instance
.
transitions
=
value
associated
Instance
.
transitions
=
value
}
}
...
...
@@ -127,10 +127,10 @@ extension UIView {
@IBInspectable
open
var
motionAlpha
:
CGFloat
?
{
get
{
return
motion
Instance
.
alpha
return
associated
Instance
.
alpha
}
set
(
value
)
{
motion
Instance
.
alpha
=
value
associated
Instance
.
alpha
=
value
}
}
}
...
...
Sources/Extensions/Motion+UIViewController.swift
View file @
baf1bf57
...
...
@@ -28,249 +28,329 @@
import
UIKit
internal
class
MotionViewControllerConfig
:
NSObject
{
var
modalAnimation
:
MotionDefaultAnimationType
=
.
auto
var
navigationAnimation
:
MotionDefaultAnimationType
=
.
auto
var
tabBarAnimation
:
MotionDefaultAnimationType
=
.
auto
fileprivate
var
AssociatedInstanceKey
:
UInt8
=
0
var
storedSnapshot
:
UIView
?
var
previousNavigationDelegate
:
UINavigationControllerDelegate
?
var
previousTabBarDelegate
:
UITabBarControllerDelegate
?
fileprivate
struct
AssociatedInstance
{
/// A reference to the modal animation.
var
modalAnimationType
:
MotionDefaultAnimationType
/// A reference to the navigation animation.
var
navigationAnimationType
:
MotionDefaultAnimationType
/// A reference to the tabBar animation.
var
tabBarAnimationType
:
MotionDefaultAnimationType
/// A reference to the stored snapshot.
var
storedSnapshot
:
UIView
?
/**
A reference to the previous navigation controller delegate
before Motion was enabled.
*/
var
previousNavigationDelegate
:
UINavigationControllerDelegate
?
/**
A reference to the previous tab bar controller delegate
before Motion was enabled.
*/
var
previousTabBarDelegate
:
UITabBarControllerDelegate
?
}
public
extension
UIViewController
{
private
struct
AssociatedKeys
{
static
var
motionConfig
=
"motionConfig"
}
extension
UIViewController
{
/// AssociatedInstance reference.
fileprivate
var
associatedInstance
:
AssociatedInstance
{
get
{
return
AssociatedObject
.
get
(
base
:
self
,
key
:
&
AssociatedInstanceKey
)
{
return
AssociatedInstance
(
modalAnimationType
:
.
auto
,
navigationAnimationType
:
.
auto
,
tabBarAnimationType
:
.
auto
,
storedSnapshot
:
nil
,
previousNavigationDelegate
:
nil
,
previousTabBarDelegate
:
nil
)
}
}
set
(
value
)
{
AssociatedObject
.
set
(
base
:
self
,
key
:
&
AssociatedInstanceKey
,
value
:
value
)
}
}
/// default motion animation type for presenting & dismissing modally
public
var
motionModalAnimationType
:
MotionDefaultAnimationType
{
get
{
return
associatedInstance
.
modalAnimationType
}
set
(
value
)
{
associatedInstance
.
modalAnimationType
=
value
}
}
@IBInspectable
public
var
motionModalAnimationTypeString
:
String
?
{
get
{
return
associatedInstance
.
modalAnimationType
.
label
}
set
(
value
)
{
associatedInstance
.
modalAnimationType
=
value
?
.
parseOne
()
??
.
auto
}
}
internal
var
motionConfig
:
MotionViewControllerConfig
{
get
{
if
let
config
=
objc_getAssociatedObject
(
self
,
&
AssociatedKeys
.
motionConfig
)
as?
MotionViewControllerConfig
{
return
config
}
let
config
=
MotionViewControllerConfig
()
self
.
motionConfig
=
config
return
config
/// used for .overFullScreen presentation
internal
var
motionStoredSnapshot
:
UIView
?
{
get
{
return
associatedInstance
.
storedSnapshot
}
set
(
value
)
{
associatedInstance
.
storedSnapshot
=
value
}
}
/**
A reference to the previous navigation controller delegate
before Motion was enabled.
*/
internal
var
previousNavigationDelegate
:
UINavigationControllerDelegate
?
{
get
{
return
associatedInstance
.
previousNavigationDelegate
}
set
(
value
)
{
associatedInstance
.
previousNavigationDelegate
=
value
}
}
set
{
objc_setAssociatedObject
(
self
,
&
AssociatedKeys
.
motionConfig
,
newValue
,
.
OBJC_ASSOCIATION_RETAIN_NONATOMIC
)
}
}
internal
var
previousNavigationDelegate
:
UINavigationControllerDelegate
?
{
get
{
return
motionConfig
.
previousNavigationDelegate
}
set
{
motionConfig
.
previousNavigationDelegate
=
newValue
}
}
/**
A reference to the previous tab bar controller delegate
before Motion was enabled.
*/
internal
var
previousTabBarDelegate
:
UITabBarControllerDelegate
?
{
get
{
return
associatedInstance
.
previousTabBarDelegate
}
set
(
value
)
{
associatedInstance
.
previousTabBarDelegate
=
value
}
}
///A boolean that indicates whether Motion is enabled or disabled.
@IBInspectable
public
var
isMotionEnabled
:
Bool
{
get
{
return
transitioningDelegate
is
Motion
}
set
(
value
)
{
guard
value
!=
isMotionEnabled
else
{
return
}
internal
var
previousTabBarDelegate
:
UITabBarControllerDelegate
?
{
get
{
return
motionConfig
.
previousTabBarDelegate
}
set
{
motionConfig
.
previousTabBarDelegate
=
newValue
}
}
if
value
{
transitioningDelegate
=
Motion
.
shared
/// used for .overFullScreen presentation
internal
var
motionStoredSnapshot
:
UIView
?
{
get
{
return
motionConfig
.
storedSnapshot
}
set
{
motionConfig
.
storedSnapshot
=
newValue
}
}
if
let
v
=
self
as?
UINavigationController
{
previousNavigationDelegate
=
v
.
delegate
v
.
delegate
=
Motion
.
shared
}
/// default motion animation type for presenting & dismissing modally
public
var
motionModalAnimationType
:
MotionDefaultAnimationType
{
get
{
return
motionConfig
.
modalAnimation
}
set
{
motionConfig
.
modalAnimation
=
newValue
}
}
if
let
v
=
self
as?
UITabBarController
{
previousTabBarDelegate
=
v
.
delegate
v
.
delegate
=
Motion
.
shared
}
}
else
{
transitioningDelegate
=
nil
@IBInspectable
public
var
motionModalAnimationTypeString
:
String
?
{
get
{
return
motionConfig
.
modalAnimation
.
label
}
set
{
motionConfig
.
modalAnimation
=
newValue
?
.
parseOne
()
??
.
auto
}
}
if
let
v
=
self
as?
UINavigationController
,
v
.
delegate
is
Motion
{
v
.
delegate
=
previousNavigationDelegate
}
@IBInspectable
public
var
isMotionEnabled
:
Bool
{
get
{
return
transitioningDelegate
is
Motion
if
let
v
=
self
as?
UITabBarController
,
v
.
delegate
is
Motion
{
v
.
delegate
=
previousTabBarDelegate
}
}
}
}
}
set
{
guard
newValue
!=
isMotionEnabled
else
{
return
}
if
newValue
{
transitioningDelegate
=
Motion
.
shared
if
let
navi
=
self
as?
UINavigationController
{
previousNavigationDelegate
=
navi
.
delegate
navi
.
delegate
=
Motion
.
shared
extension
UINavigationController
{
/// Default motion animation type for push and pop within the navigation controller.
public
var
motionNavigationAnimationType
:
MotionDefaultAnimationType
{
get
{
return
associatedInstance
.
navigationAnimationType
}
if
let
tab
=
self
as?
UITabBarController
{
previousTabBarDelegate
=
tab
.
delegate
tab
.
delegate
=
Motion
.
shared
set
(
value
)
{
associatedInstance
.
navigationAnimationType
=
value
}
}
else
{
transitioningDelegate
=
nil
if
let
navi
=
self
as?
UINavigationController
,
navi
.
delegate
is
Motion
{
navi
.
delegate
=
previousNavigationDelegate
}
/// A String representation for the motionNavigationAnimationType.
@IBInspectable
public
var
motionNavigationAnimationTypeString
:
String
?
{
get
{
return
associatedInstance
.
navigationAnimationType
.
label
}
if
let
tab
=
self
as?
UITabBarController
,
tab
.
delegate
is
Motion
{
tab
.
delegate
=
previousTabBarDelegate
set
(
value
)
{
associatedInstance
.
navigationAnimationType
=
value
?
.
parseOne
()
??
.
auto
}
}
}
}
}
extension
UINavigationController
{
/// default motion animation type for push and pop within the navigation controller
public
var
motionNavigationAnimationType
:
MotionDefaultAnimationType
{
get
{
return
motionConfig
.
navigationAnimation
}
set
{
motionConfig
.
navigationAnimation
=
newValue
}
}
@IBInspectable
public
var
motionNavigationAnimationTypeString
:
String
?
{
get
{
return
motionConfig
.
navigationAnimation
.
label
}
set
{
motionConfig
.
navigationAnimation
=
newValue
?
.
parseOne
()
??
.
auto
}
}
}
extension
UITabBarController
{
/// default motion animation type for switching tabs within the tab bar controller
public
var
motionTabBarAnimationType
:
MotionDefaultAnimationType
{
get
{
return
motionConfig
.
tabBarAnimation
}
set
{
motionConfig
.
tabBarAnimation
=
newValue
}
}
@IBInspectable
public
var
motionTabBarAnimationTypeString
:
String
?
{
get
{
return
motionConfig
.
tabBarAnimation
.
label
}
set
{
motionConfig
.
tabBarAnimation
=
newValue
?
.
parseOne
()
??
.
auto
}
}
/// Default motion animation type for switching tabs within the tab bar controller.
public
var
motionTabBarAnimationType
:
MotionDefaultAnimationType
{
get
{
return
associatedInstance
.
tabBarAnimationType
}
set
(
value
)
{
associatedInstance
.
tabBarAnimationType
=
value
}
}
/// A String representation for the motionTabBarAnimationTypeString.
@IBInspectable
public
var
motionTabBarAnimationTypeString
:
String
?
{
get
{
return
associatedInstance
.
tabBarAnimationType
.
label
}
set
(
value
)
{
associatedInstance
.
tabBarAnimationType
=
value
?
.
parseOne
()
??
.
auto
}
}
}
extension
UIViewController
{
@available(*, deprecated: 0.1.4, message: "use motion_dismissViewController instead")
@IBAction
public
func
ht_dismiss
(
_
sender
:
UIView
)
{
motion_dismissViewController
()
}
@available(*, deprecated: 0.1.4, message: "use motion_replaceViewController(with:)
instead
")
public func motionReplaceViewController(with next: UIViewController) {
motion_replaceViewController(with: next)
}
/**
Dismiss the current view controller with animation. Will perform a navigationController.popViewController
if the current view controller is contained inside a navigationController
*/
@IBAction public func motion_dismissViewController() {
if let navigationController = navigationController, navigationController.viewControllers.first != self {
navigationController.popViewController(animated: true)
} else {
dismiss(animated: true, completion: nil)
/**
Dismiss the current view controller with animation. Will perform a
navigationController.popViewController if the current view controller
is contained inside a navigationController
*/
@IBAction
public
func
motion_dismissViewController
()
{
if
let
navigationController
=
navigationController
,
navigationController
.
viewControllers
.
first
!=
self
{
navigationController
.
popViewController
(
animated
:
true
)
}
else
{
dismiss
(
animated
:
true
,
completion
:
nil
)
}
}
}
/**
Unwind to the root view controller using Motion
*/
@IBAction public func motion_unwindToRootViewController() {
motion_unwindToViewController { $0.presentingViewController == nil }
}
/**
Unwind to a specific view controller using Motion
*/
public func motion_unwindToViewController(_ toViewController: UIViewController) {
motion_unwindToViewController { $0 == toViewController }
}
/**
Unwind to a view controller that responds to the given selector using Motion
*/
public func motion_unwindToViewController(withSelector: Selector) {
motion_unwindToViewController { $0.responds(to: withSelector) }
}
/**
Unwind to a view controller with given class using Motion
*/
public func motion_unwindToViewController(withClass: AnyClass) {
motion_unwindToViewController { $0.isKind(of: withClass) }
}
/**
Unwind to a view controller that the matchBlock returns true on.
*/
public func motion_unwindToViewController(withMatchBlock: (UIViewController) -> Bool) {
var target: UIViewController? = nil
var current: UIViewController? = self
while target == nil && current != nil {
if let childViewControllers = (current as? UINavigationController)?.childViewControllers ?? current!.navigationController?.childViewControllers {
for vc in childViewControllers.reversed() {
if vc != self, withMatchBlock(vc) {
target = vc
break
}
/// Unwind to the root view controller using Motion.
@IBAction
public
func
motion_unwindToRootViewController
()
{
motion_unwindToViewController
{
$0
.
presentingViewController
==
nil
}
}
/// Unwind to a specific view controller using Motion.
public
func
motion_unwindToViewController
(
_
toViewController
:
UIViewController
)
{
motion_unwindToViewController
{
$0
==
toViewController
}
}
/// Unwind to a view controller that responds to the given selector using Motion.
public
func
motion_unwindToViewController
(
withSelector
:
Selector
)
{
motion_unwindToViewController
{
$0
.
responds
(
to
:
withSelector
)
}
}
/// Unwind to a view controller with given class using Motion
public
func
motion_unwindToViewController
(
withClass
:
AnyClass
)
{
motion_unwindToViewController
{
$0
.
isKind
(
of
:
withClass
)
}
}
/// Unwind to a view controller that the matchBlock returns true on.
public
func
motion_unwindToViewController
(
withMatchBlock
:
(
UIViewController
)
->
Bool
)
{
var
target
:
UIViewController
?
var
current
:
UIViewController
?
=
self
while
nil
==
target
&&
nil
!=
current
{
if
let
childViewControllers
=
(
current
as?
UINavigationController
)?
.
childViewControllers
??
current
!.
navigationController
?
.
childViewControllers
{
for
v
in
childViewControllers
.
reversed
()
{
if
self
!=
v
,
withMatchBlock
(
v
)
{
target
=
v
break
}
}
}
guard
nil
==
target
else
{
continue
}
current
=
current
?
.
presentingViewController
guard
let
v
=
current
,
withMatchBlock
(
v
)
else
{
continue
}
target
=
v
}
}
if target == nil {
current = current!.presentingViewController
if let vc = current, withMatchBlock(vc) == true {
target = vc
guard
let
v
=
target
else
{
return
}
}
}
if let target = target {
if target.presentedViewController != nil {
_ = target.navigationController?.popToViewController(target, animated: false)
guard
nil
!=
v
.
presentedViewController
else
{
v
.
navigationController
?
.
popToViewController
(
v
,
animated
:
true
)
return
}
v
.
navigationController
?
.
popToViewController
(
v
,
animated
:
false
)
let
fromVC
=
self
.
navigationController
??
self
let toVC = target.navigationController ?? target
if target.presentedViewController != fromVC {
// UIKit's UIViewController.dismiss will jump to target.presentedViewController then perform the dismiss.
// We overcome this behavior by inserting a snapshot into target.presentedViewController
// And also force Motion to use the current VC as the fromViewController
Motion.shared.fromViewController = fromVC
let snapshotView = fromVC.view.snapshotView(afterScreenUpdates: true)!
toVC.presentedViewController!.view.addSubview(snapshotView)
let
toVC
=
v
.
navigationController
??
v
if
v
.
presentedViewController
!=
fromVC
{
/**
UIKit's UIViewController.dismiss will jump to target.presentedViewController then perform the dismiss.
We overcome this behavior by inserting a snapshot into target.presentedViewController
And also force Motion to use the current view controller as the fromViewController.
*/
Motion
.
shared
.
fromViewController
=
fromVC
guard
let
snapshot
=
fromVC
.
view
.
snapshotView
(
afterScreenUpdates
:
true
)
else
{
return
}
toVC
.
presentedViewController
?
.
view
.
addSubview
(
snapshot
)
}
toVC
.
dismiss
(
animated
:
true
,
completion
:
nil
)
} else {
_ = target.navigationController?.popToViewController(target, animated: true)
}
} else {
// unwind target not found
}
}
/**
Replace the current view controller with another VC on the navigation/modal stack.
*/
public func motion_replaceViewController(with next: UIViewController) {
if Motion.shared.transitioning {
print("
motion_replaceViewController
cancelled
because
Motion
was
doing
a
transition
.
Use
Motion
.
shared
.
cancel
(
animated
:
false
)
or
Motion
.
shared
.
end
(
animated
:
false
)
to
stop
the
transition
first
before
calling
motion_replaceViewController
.
")
return
}
if let navigationController = navigationController {
var vcs = navigationController.childViewControllers
if !vcs.isEmpty {
vcs.removeLast()
vcs.append(next)
}
if navigationController.isMotionEnabled {
Motion.shared.forceNotInteractive = true
}
navigationController.setViewControllers(vcs, animated: true)
} else if let container = view.superview {
let parentVC = presentingViewController
Motion.shared.transition(from: self, to: next, in: container) { finished in
if finished {
UIApplication.shared.keyWindow?.addSubview(next.view)
if let parentVC = parentVC {
self.dismiss(animated: false) {
parentVC.present(next, animated: false, completion:nil)
/**
Replace the current view controller with another view controller on the
navigation/modal stack.
*/
public
func
motion_replaceViewController
(
with
next
:
UIViewController
)
{
guard
!
Motion
.
shared
.
isTransitioning
else
{
print
(
"motion_replaceViewController cancelled because Motion was doing a transition. Use Motion.shared.cancel(animated:false) or Motion.shared.end(animated:false) to stop the transition first before calling motion_replaceViewController."
)
return
}
if
let
navigationController
=
navigationController
{
var
v
=
navigationController
.
childViewControllers
if
!
v
.
isEmpty
{
v
.
removeLast
()
v
.
append
(
next
)
}
if
navigationController
.
isMotionEnabled
{
Motion
.
shared
.
forceNotInteractive
=
true
}
navigationController
.
setViewControllers
(
v
,
animated
:
true
)
}
else
if
let
container
=
view
.
superview
{
let
parentVC
=
presentingViewController
Motion
.
shared
.
transition
(
from
:
self
,
to
:
next
,
in
:
container
)
{
[
weak
self
]
(
isFinished
)
in
guard
isFinished
else
{
return
}
UIApplication
.
shared
.
keyWindow
?
.
addSubview
(
next
.
view
)
guard
let
parentVC
=
parentVC
else
{
UIApplication
.
shared
.
keyWindow
?
.
rootViewController
=
next
return
}
self
?
.
dismiss
(
animated
:
false
)
{
parentVC
.
present
(
next
,
animated
:
false
,
completion
:
nil
)
}
}
} else {
UIApplication.shared.keyWindow?.rootViewController = next
}
}
}
}
}
}
Sources/Motion.swift
View file @
baf1bf57
...
...
@@ -62,7 +62,7 @@ public class Motion: MotionController {
/// progress of the current transition. 0 if no transition is happening
public
override
var
progress
:
Double
{
didSet
{
if
t
ransitioning
{
if
isT
ransitioning
{
transitionContext
?
.
updateInteractiveTransition
(
CGFloat
(
progress
))
}
}
...
...
@@ -70,7 +70,7 @@ public class Motion: MotionController {
public
var
isAnimating
:
Bool
=
false
/// a UIViewControllerContextTransitioning object provided by UIKit,
/// might be nil when
t
ransitioning. This happens when calling motionReplaceViewController
/// might be nil when
isT
ransitioning. This happens when calling motionReplaceViewController
internal
weak
var
transitionContext
:
UIViewControllerContextTransitioning
?
internal
var
fullScreenSnapshot
:
UIView
!
...
...
@@ -129,7 +129,7 @@ public extension Motion {
// internal methods for transition
internal
extension
Motion
{
func
start
()
{
guard
t
ransitioning
else
{
return
}
guard
isT
ransitioning
else
{
return
}
if
let
fvc
=
fromViewController
,
let
tvc
=
toViewController
{
closureProcessForMotionDelegate
(
vc
:
fvc
)
{
$0
.
motionWillStartTransition
?()
...
...
@@ -214,7 +214,7 @@ internal extension Motion {
}
override
func
complete
(
finished
:
Bool
)
{
guard
t
ransitioning
else
{
return
}
guard
isT
ransitioning
else
{
return
}
context
.
clean
()
if
finished
&&
presenting
&&
toOverFullScreen
{
...
...
@@ -304,7 +304,7 @@ internal extension Motion {
// custom transition helper, used in motion_replaceViewController
internal
extension
Motion
{
func
transition
(
from
:
UIViewController
,
to
:
UIViewController
,
in
view
:
UIView
,
completion
:
((
Bool
)
->
Void
)?
=
nil
)
{
guard
!
t
ransitioning
else
{
return
}
guard
!
isT
ransitioning
else
{
return
}
presenting
=
true
transitionContainer
=
view
fromViewController
=
from
...
...
@@ -341,7 +341,7 @@ internal extension Motion {
extension
Motion
:
UIViewControllerAnimatedTransitioning
{
public
func
animateTransition
(
using
context
:
UIViewControllerContextTransitioning
)
{
guard
!
t
ransitioning
else
{
return
}
guard
!
isT
ransitioning
else
{
return
}
transitionContext
=
context
fromViewController
=
fromViewController
??
context
.
viewController
(
forKey
:
.
from
)
toViewController
=
toViewController
??
context
.
viewController
(
forKey
:
.
to
)
...
...
Sources/MotionController.swift
View file @
baf1bf57
...
...
@@ -40,7 +40,7 @@ public class MotionController: NSObject {
/// progress of the current transition. 0 if no transition is happening
public
internal(set)
var
progress
:
Double
=
0
{
didSet
{
if
t
ransitioning
{
if
isT
ransitioning
{
if
let
progressUpdateObservers
=
progressUpdateObservers
{
for
observer
in
progressUpdateObservers
{
observer
.
motionDidUpdateProgress
(
progress
:
progress
)
...
...
@@ -61,12 +61,12 @@ public class MotionController: NSObject {
}
}
/// whether or not we are doing a transition
public
var
t
ransitioning
:
Bool
{
public
var
isT
ransitioning
:
Bool
{
return
transitionContainer
!=
nil
}
/// container we created to hold all animating views, will be a subview of the
/// transitionContainer when
t
ransitioning
/// transitionContainer when
isT
ransitioning
public
internal(set)
var
container
:
UIView
!
/// this is the container supplied by UIKit
...
...
@@ -98,7 +98,7 @@ public class MotionController: NSObject {
}
}
func
displayUpdate
(
_
link
:
CADisplayLink
)
{
if
t
ransitioning
,
duration
>
0
,
let
beginTime
=
beginTime
{
if
isT
ransitioning
,
duration
>
0
,
let
beginTime
=
beginTime
{
let
elapsedTime
=
CACurrentMediaTime
()
-
beginTime
if
elapsedTime
>
duration
{
...
...
@@ -138,7 +138,7 @@ public extension MotionController {
- progress: the current progress, must be between -1...1
*/
public
func
update
(
progress
:
Double
)
{
guard
t
ransitioning
else
{
return
}
guard
isT
ransitioning
else
{
return
}
self
.
beginTime
=
nil
self
.
progress
=
max
(
-
1
,
min
(
1
,
progress
))
}
...
...
@@ -149,7 +149,7 @@ public extension MotionController {
current state to the **end** state
*/
public
func
end
(
animate
:
Bool
=
true
)
{
guard
t
ransitioning
else
{
return
}
guard
isT
ransitioning
else
{
return
}
if
!
animate
{
self
.
complete
(
finished
:
true
)
return
...
...
@@ -167,7 +167,7 @@ public extension MotionController {
current state to the **begining** state
*/
public
func
cancel
(
animate
:
Bool
=
true
)
{
guard
t
ransitioning
else
{
return
}
guard
isT
ransitioning
else
{
return
}
if
!
animate
{
self
.
complete
(
finished
:
false
)
return
...
...
@@ -196,7 +196,7 @@ public extension MotionController {
- view: the view to override to
*/
public
func
apply
(
modifiers
:
[
MotionTransition
],
to
view
:
UIView
)
{
guard
t
ransitioning
else
{
return
}
guard
isT
ransitioning
else
{
return
}
let
targetState
=
MotionTargetState
(
modifiers
:
modifiers
)
if
let
otherView
=
self
.
context
.
pairedView
(
for
:
view
)
{
for
animator
in
self
.
animators
{
...
...
@@ -233,7 +233,7 @@ internal extension MotionController {
/// must have transitionContainer set already
/// subclass should call context.set(fromViews:toViews) after inserting fromViews & toViews into the container
func
prepareForTransition
()
{
guard
t
ransitioning
else
{
fatalError
()
}
guard
isT
ransitioning
else
{
fatalError
()
}
plugins
=
Motion
.
enabledPlugins
.
map
({
return
$0
.
init
()
})
processors
=
[
IgnoreSubviewModifiersPreprocessor
(),
...
...
@@ -273,14 +273,14 @@ internal extension MotionController {
}
func
processContext
()
{
guard
t
ransitioning
else
{
fatalError
()
}
guard
isT
ransitioning
else
{
fatalError
()
}
for
processor
in
processors
{
processor
.
process
(
fromViews
:
context
.
fromViews
,
toViews
:
context
.
toViews
)
}
}
func
prepareForAnimation
()
{
guard
t
ransitioning
else
{
fatalError
()
}
guard
isT
ransitioning
else
{
fatalError
()
}
animatingViews
=
[([
UIView
],
[
UIView
])]()
for
animator
in
animators
{
let
currentFromViews
=
context
.
fromViews
.
filter
{
(
view
:
UIView
)
->
Bool
in
...
...
@@ -296,7 +296,7 @@ internal extension MotionController {
/// Actually animate the views
/// subclass should call `prepareForTransition` & `prepareForAnimation` before calling `animate`
func
animate
()
{
guard
t
ransitioning
else
{
fatalError
()
}
guard
isT
ransitioning
else
{
fatalError
()
}
for
(
currentFromViews
,
currentToViews
)
in
animatingViews
{
// auto hide all animated views
for
view
in
currentFromViews
{
...
...
@@ -328,7 +328,7 @@ internal extension MotionController {
}
func
complete
(
after
:
TimeInterval
,
finishing
:
Bool
)
{
guard
t
ransitioning
else
{
fatalError
()
}
guard
isT
ransitioning
else
{
fatalError
()
}
if
after
<=
0.001
{
complete
(
finished
:
finishing
)
return
...
...
@@ -340,7 +340,7 @@ internal extension MotionController {
}
func
complete
(
finished
:
Bool
)
{
guard
t
ransitioning
else
{
fatalError
()
}
guard
isT
ransitioning
else
{
fatalError
()
}
for
animator
in
animators
{
animator
.
clean
()
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment