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 @@
...
@@ -53,7 +53,7 @@
/* Begin PBXFileReference section */
/* Begin PBXFileReference section */
963150D11EE50DA6002B0D42
/* Motion+Obj-C.swift */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.swift
;
path
=
"Motion+Obj-C.swift"
;
sourceTree
=
"<group>"
;
};
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>"
;
};
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>"
;
};
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>"
;
};
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>"
;
};
968989DD1EE6633E003B8F3D
/* MotionAnimator.swift */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.swift
;
path
=
MotionAnimator.swift
;
sourceTree
=
"<group>"
;
};
...
@@ -117,6 +117,7 @@
...
@@ -117,6 +117,7 @@
96AEB6671EE4610F009A3BE0
/* MotionDefaultAnimator.swift */
,
96AEB6671EE4610F009A3BE0
/* MotionDefaultAnimator.swift */
,
96AEB6681EE4610F009A3BE0
/* MotionViewPropertyViewContext.swift */
,
96AEB6681EE4610F009A3BE0
/* MotionViewPropertyViewContext.swift */
,
968989B81EE5B34B003B8F3D
/* MotionHasInsertOrder.swift */
,
968989B81EE5B34B003B8F3D
/* MotionHasInsertOrder.swift */
,
963150D91EE51EB4002B0D42
/* MotionAnimationFillMode.swift */
,
);
);
path
=
Animator
;
path
=
Animator
;
sourceTree
=
"<group>"
;
sourceTree
=
"<group>"
;
...
@@ -141,7 +142,6 @@
...
@@ -141,7 +142,6 @@
96AEB6731EE4610F009A3BE0
/* Motion+UIKit.swift */
,
96AEB6731EE4610F009A3BE0
/* Motion+UIKit.swift */
,
96AEB6741EE4610F009A3BE0
/* Motion+UIView.swift */
,
96AEB6741EE4610F009A3BE0
/* Motion+UIView.swift */
,
96AEB6751EE4610F009A3BE0
/* Motion+UIViewController.swift */
,
96AEB6751EE4610F009A3BE0
/* Motion+UIViewController.swift */
,
963150D91EE51EB4002B0D42
/* MotionAnimationFillMode.swift */
,
);
);
path
=
Extensions
;
path
=
Extensions
;
sourceTree
=
"<group>"
;
sourceTree
=
"<group>"
;
...
...
Sources/Extensions/Motion+UIView.swift
View file @
baf1bf57
...
@@ -49,9 +49,9 @@ internal extension UIView {
...
@@ -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.
/// A boolean indicating whether Motion is enabled.
fileprivate
var
isEnabled
:
Bool
fileprivate
var
isEnabled
:
Bool
...
@@ -69,15 +69,15 @@ fileprivate struct MotionInstance {
...
@@ -69,15 +69,15 @@ fileprivate struct MotionInstance {
}
}
extension
UIView
{
extension
UIView
{
///
Motion
Instance reference.
///
Associated
Instance reference.
fileprivate
var
motionInstance
:
Motion
Instance
{
fileprivate
var
associatedInstance
:
Associated
Instance
{
get
{
get
{
return
AssociatedObject
.
get
(
base
:
self
,
key
:
&
Motion
InstanceKey
)
{
return
AssociatedObject
.
get
(
base
:
self
,
key
:
&
Associated
InstanceKey
)
{
return
Motion
Instance
(
isEnabled
:
true
,
identifier
:
nil
,
animations
:
nil
,
transitions
:
nil
,
alpha
:
1
)
return
Associated
Instance
(
isEnabled
:
true
,
identifier
:
nil
,
animations
:
nil
,
transitions
:
nil
,
alpha
:
1
)
}
}
}
}
set
(
value
)
{
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 {
...
@@ -85,10 +85,10 @@ extension UIView {
@IBInspectable
@IBInspectable
public
var
isMotionEnabled
:
Bool
{
public
var
isMotionEnabled
:
Bool
{
get
{
get
{
return
motion
Instance
.
isEnabled
return
associated
Instance
.
isEnabled
}
}
set
(
value
)
{
set
(
value
)
{
motion
Instance
.
isEnabled
=
value
associated
Instance
.
isEnabled
=
value
}
}
}
}
...
@@ -96,30 +96,30 @@ extension UIView {
...
@@ -96,30 +96,30 @@ extension UIView {
@IBInspectable
@IBInspectable
open
var
motionIdentifier
:
String
?
{
open
var
motionIdentifier
:
String
?
{
get
{
get
{
return
motion
Instance
.
identifier
return
associated
Instance
.
identifier
}
}
set
(
value
)
{
set
(
value
)
{
motion
Instance
.
identifier
=
value
associated
Instance
.
identifier
=
value
}
}
}
}
/// The animations to run.
/// The animations to run.
open
var
motionAnimations
:
[
MotionAnimation
]?
{
open
var
motionAnimations
:
[
MotionAnimation
]?
{
get
{
get
{
return
motion
Instance
.
animations
return
associated
Instance
.
animations
}
}
set
(
value
)
{
set
(
value
)
{
motion
Instance
.
animations
=
value
associated
Instance
.
animations
=
value
}
}
}
}
/// The animations to run while in transition.
/// The animations to run while in transition.
open
var
motionTransitions
:
[
MotionTransition
]?
{
open
var
motionTransitions
:
[
MotionTransition
]?
{
get
{
get
{
return
motion
Instance
.
transitions
return
associated
Instance
.
transitions
}
}
set
(
value
)
{
set
(
value
)
{
motion
Instance
.
transitions
=
value
associated
Instance
.
transitions
=
value
}
}
}
}
...
@@ -127,10 +127,10 @@ extension UIView {
...
@@ -127,10 +127,10 @@ extension UIView {
@IBInspectable
@IBInspectable
open
var
motionAlpha
:
CGFloat
?
{
open
var
motionAlpha
:
CGFloat
?
{
get
{
get
{
return
motion
Instance
.
alpha
return
associated
Instance
.
alpha
}
}
set
(
value
)
{
set
(
value
)
{
motion
Instance
.
alpha
=
value
associated
Instance
.
alpha
=
value
}
}
}
}
}
}
...
...
Sources/Extensions/Motion+UIViewController.swift
View file @
baf1bf57
...
@@ -28,249 +28,329 @@
...
@@ -28,249 +28,329 @@
import
UIKit
import
UIKit
internal
class
MotionViewControllerConfig
:
NSObject
{
fileprivate
var
AssociatedInstanceKey
:
UInt8
=
0
var
modalAnimation
:
MotionDefaultAnimationType
=
.
auto
var
navigationAnimation
:
MotionDefaultAnimationType
=
.
auto
var
tabBarAnimation
:
MotionDefaultAnimationType
=
.
auto
var
storedSnapshot
:
UIView
?
fileprivate
struct
AssociatedInstance
{
var
previousNavigationDelegate
:
UINavigationControllerDelegate
?
/// A reference to the modal animation.
var
previousTabBarDelegate
:
UITabBarControllerDelegate
?
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
{
extension
UIViewController
{
private
struct
AssociatedKeys
{
/// AssociatedInstance reference.
static
var
motionConfig
=
"motionConfig"
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
{
/// used for .overFullScreen presentation
get
{
internal
var
motionStoredSnapshot
:
UIView
?
{
if
let
config
=
objc_getAssociatedObject
(
self
,
&
AssociatedKeys
.
motionConfig
)
as?
MotionViewControllerConfig
{
get
{
return
config
return
associatedInstance
.
storedSnapshot
}
}
let
config
=
MotionViewControllerConfig
()
set
(
value
)
{
self
.
motionConfig
=
config
associatedInstance
.
storedSnapshot
=
value
return
config
}
}
/**
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
}
A reference to the previous tab bar controller delegate
set
{
motionConfig
.
previousNavigationDelegate
=
newValue
}
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
?
{
if
value
{
get
{
return
motionConfig
.
previousTabBarDelegate
}
transitioningDelegate
=
Motion
.
shared
set
{
motionConfig
.
previousTabBarDelegate
=
newValue
}
}
/// used for .overFullScreen presentation
if
let
v
=
self
as?
UINavigationController
{
internal
var
motionStoredSnapshot
:
UIView
?
{
previousNavigationDelegate
=
v
.
delegate
get
{
return
motionConfig
.
storedSnapshot
}
v
.
delegate
=
Motion
.
shared
set
{
motionConfig
.
storedSnapshot
=
newValue
}
}
}
/// default motion animation type for presenting & dismissing modally
if
let
v
=
self
as?
UITabBarController
{
public
var
motionModalAnimationType
:
MotionDefaultAnimationType
{
previousTabBarDelegate
=
v
.
delegate
get
{
return
motionConfig
.
modalAnimation
}
v
.
delegate
=
Motion
.
shared
set
{
motionConfig
.
modalAnimation
=
newValue
}
}
}
}
else
{
transitioningDelegate
=
nil
@IBInspectable
public
var
motionModalAnimationTypeString
:
String
?
{
if
let
v
=
self
as?
UINavigationController
,
v
.
delegate
is
Motion
{
get
{
return
motionConfig
.
modalAnimation
.
label
}
v
.
delegate
=
previousNavigationDelegate
set
{
motionConfig
.
modalAnimation
=
newValue
?
.
parseOne
()
??
.
auto
}
}
}
@IBInspectable
public
var
isMotionEnabled
:
Bool
{
if
let
v
=
self
as?
UITabBarController
,
v
.
delegate
is
Motion
{
get
{
v
.
delegate
=
previousTabBarDelegate
return
transitioningDelegate
is
Motion
}
}
}
}
}
}
set
{
extension
UINavigationController
{
guard
newValue
!=
isMotionEnabled
else
{
return
}
/// Default motion animation type for push and pop within the navigation controller.
if
newValue
{
public
var
motionNavigationAnimationType
:
MotionDefaultAnimationType
{
transitioningDelegate
=
Motion
.
shared
get
{
if
let
navi
=
self
as?
UINavigationController
{
return
associatedInstance
.
navigationAnimationType
previousNavigationDelegate
=
navi
.
delegate
navi
.
delegate
=
Motion
.
shared
}
}
if
let
tab
=
self
as?
UITabBarController
{
set
(
value
)
{
previousTabBarDelegate
=
tab
.
delegate
associatedInstance
.
navigationAnimationType
=
value
tab
.
delegate
=
Motion
.
shared
}
}
}
else
{
}
transitioningDelegate
=
nil
if
let
navi
=
self
as?
UINavigationController
,
navi
.
delegate
is
Motion
{
/// A String representation for the motionNavigationAnimationType.
navi
.
delegate
=
previousNavigationDelegate
@IBInspectable
public
var
motionNavigationAnimationTypeString
:
String
?
{
get
{
return
associatedInstance
.
navigationAnimationType
.
label
}
}
if
let
tab
=
self
as?
UITabBarController
,
tab
.
delegate
is
Motion
{
set
(
value
)
{
tab
.
delegate
=
previousTabBarDelegate
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
{
extension
UITabBarController
{
/// default motion animation type for switching tabs within the tab bar controller
/// Default motion animation type for switching tabs within the tab bar controller.
public
var
motionTabBarAnimationType
:
MotionDefaultAnimationType
{
public
var
motionTabBarAnimationType
:
MotionDefaultAnimationType
{
get
{
return
motionConfig
.
tabBarAnimation
}
get
{
set
{
motionConfig
.
tabBarAnimation
=
newValue
}
return
associatedInstance
.
tabBarAnimationType
}
}
set
(
value
)
{
@IBInspectable
public
var
motionTabBarAnimationTypeString
:
String
?
{
associatedInstance
.
tabBarAnimationType
=
value
get
{
return
motionConfig
.
tabBarAnimation
.
label
}
}
set
{
motionConfig
.
tabBarAnimation
=
newValue
?
.
parseOne
()
??
.
auto
}
}
}
/// 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
{
extension
UIViewController
{
@available(*, deprecated: 0.1.4, message: "use motion_dismissViewController instead")
/**
@IBAction
public
func
ht_dismiss
(
_
sender
:
UIView
)
{
Dismiss the current view controller with animation. Will perform a
motion_dismissViewController
()
navigationController.popViewController if the current view controller
}
is contained inside a navigationController
*/
@available(*, deprecated: 0.1.4, message: "use motion_replaceViewController(with:)
instead
")
@IBAction
public func motionReplaceViewController(with next: UIViewController) {
public
func
motion_dismissViewController
()
{
motion_replaceViewController(with: next)
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
Unwind to the root view controller using Motion
public
func
motion_unwindToRootViewController
()
{
*/
motion_unwindToViewController
{
$0
.
presentingViewController
==
nil
}
@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 specific view controller using Motion
}
*/
public func motion_unwindToViewController(_ toViewController: UIViewController) {
/// Unwind to a view controller that responds to the given selector using Motion.
motion_unwindToViewController { $0 == toViewController }
public
func
motion_unwindToViewController
(
withSelector
:
Selector
)
{
}
motion_unwindToViewController
{
$0
.
responds
(
to
:
withSelector
)
}
}
/**
Unwind to a view controller that responds to the given selector using Motion
/// Unwind to a view controller with given class using Motion
*/
public
func
motion_unwindToViewController
(
withClass
:
AnyClass
)
{
public func motion_unwindToViewController(withSelector: Selector) {
motion_unwindToViewController
{
$0
.
isKind
(
of
:
withClass
)
}
motion_unwindToViewController { $0.responds(to: withSelector) }
}
}
/// Unwind to a view controller that the matchBlock returns true on.
/**
public
func
motion_unwindToViewController
(
withMatchBlock
:
(
UIViewController
)
->
Bool
)
{
Unwind to a view controller with given class using Motion
var
target
:
UIViewController
?
*/
var
current
:
UIViewController
?
=
self
public func motion_unwindToViewController(withClass: AnyClass) {
motion_unwindToViewController { $0.isKind(of: withClass) }
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
)
{
Unwind to a view controller that the matchBlock returns true on.
target
=
v
*/
break
public func motion_unwindToViewController(withMatchBlock: (UIViewController) -> Bool) {
}
var target: UIViewController? = nil
}
var current: UIViewController? = self
}
while target == nil && current != nil {
guard
nil
==
target
else
{
if let childViewControllers = (current as? UINavigationController)?.childViewControllers ?? current!.navigationController?.childViewControllers {
continue
for vc in childViewControllers.reversed() {
}
if vc != self, withMatchBlock(vc) {
target = vc
current
=
current
?
.
presentingViewController
break
}
guard
let
v
=
current
,
withMatchBlock
(
v
)
else
{
continue
}
target
=
v
}
}
}
if target == nil {
guard
let
v
=
target
else
{
current = current!.presentingViewController
return
if let vc = current, withMatchBlock(vc) == true {
target = vc
}
}
}
}
guard
nil
!=
v
.
presentedViewController
else
{
v
.
navigationController
?
.
popToViewController
(
v
,
animated
:
true
)
if let target = target {
return
if target.presentedViewController != nil {
}
_ = target.navigationController?.popToViewController(target, animated: false)
v
.
navigationController
?
.
popToViewController
(
v
,
animated
:
false
)
let
fromVC
=
self
.
navigationController
??
self
let
fromVC
=
self
.
navigationController
??
self
let toVC = target.navigationController ?? target
let
toVC
=
v
.
navigationController
??
v
if target.presentedViewController != fromVC {
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
UIKit's UIViewController.dismiss will jump to target.presentedViewController then perform the dismiss.
// And also force Motion to use the current VC as the fromViewController
We overcome this behavior by inserting a snapshot into target.presentedViewController
Motion.shared.fromViewController = fromVC
And also force Motion to use the current view controller as the fromViewController.
let snapshotView = fromVC.view.snapshotView(afterScreenUpdates: true)!
*/
toVC.presentedViewController!.view.addSubview(snapshotView)
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
)
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 {
Replace the current view controller with another view controller on the
vcs.removeLast()
navigation/modal stack.
vcs.append(next)
*/
}
public
func
motion_replaceViewController
(
with
next
:
UIViewController
)
{
if navigationController.isMotionEnabled {
guard
!
Motion
.
shared
.
isTransitioning
else
{
Motion.shared.forceNotInteractive = true
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
navigationController.setViewControllers(vcs, animated: true)
}
} else if let container = view.superview {
let parentVC = presentingViewController
if
let
navigationController
=
navigationController
{
Motion.shared.transition(from: self, to: next, in: container) { finished in
var
v
=
navigationController
.
childViewControllers
if finished {
UIApplication.shared.keyWindow?.addSubview(next.view)
if
!
v
.
isEmpty
{
v
.
removeLast
()
if let parentVC = parentVC {
v
.
append
(
next
)
self.dismiss(animated: false) {
}
parentVC.present(next, animated: false, completion:nil)
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 {
...
@@ -62,7 +62,7 @@ public class Motion: MotionController {
/// progress of the current transition. 0 if no transition is happening
/// progress of the current transition. 0 if no transition is happening
public
override
var
progress
:
Double
{
public
override
var
progress
:
Double
{
didSet
{
didSet
{
if
t
ransitioning
{
if
isT
ransitioning
{
transitionContext
?
.
updateInteractiveTransition
(
CGFloat
(
progress
))
transitionContext
?
.
updateInteractiveTransition
(
CGFloat
(
progress
))
}
}
}
}
...
@@ -70,7 +70,7 @@ public class Motion: MotionController {
...
@@ -70,7 +70,7 @@ public class Motion: MotionController {
public
var
isAnimating
:
Bool
=
false
public
var
isAnimating
:
Bool
=
false
/// a UIViewControllerContextTransitioning object provided by UIKit,
/// 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
weak
var
transitionContext
:
UIViewControllerContextTransitioning
?
internal
var
fullScreenSnapshot
:
UIView
!
internal
var
fullScreenSnapshot
:
UIView
!
...
@@ -129,7 +129,7 @@ public extension Motion {
...
@@ -129,7 +129,7 @@ public extension Motion {
// internal methods for transition
// internal methods for transition
internal
extension
Motion
{
internal
extension
Motion
{
func
start
()
{
func
start
()
{
guard
t
ransitioning
else
{
return
}
guard
isT
ransitioning
else
{
return
}
if
let
fvc
=
fromViewController
,
let
tvc
=
toViewController
{
if
let
fvc
=
fromViewController
,
let
tvc
=
toViewController
{
closureProcessForMotionDelegate
(
vc
:
fvc
)
{
closureProcessForMotionDelegate
(
vc
:
fvc
)
{
$0
.
motionWillStartTransition
?()
$0
.
motionWillStartTransition
?()
...
@@ -214,7 +214,7 @@ internal extension Motion {
...
@@ -214,7 +214,7 @@ internal extension Motion {
}
}
override
func
complete
(
finished
:
Bool
)
{
override
func
complete
(
finished
:
Bool
)
{
guard
t
ransitioning
else
{
return
}
guard
isT
ransitioning
else
{
return
}
context
.
clean
()
context
.
clean
()
if
finished
&&
presenting
&&
toOverFullScreen
{
if
finished
&&
presenting
&&
toOverFullScreen
{
...
@@ -304,7 +304,7 @@ internal extension Motion {
...
@@ -304,7 +304,7 @@ internal extension Motion {
// custom transition helper, used in motion_replaceViewController
// custom transition helper, used in motion_replaceViewController
internal
extension
Motion
{
internal
extension
Motion
{
func
transition
(
from
:
UIViewController
,
to
:
UIViewController
,
in
view
:
UIView
,
completion
:
((
Bool
)
->
Void
)?
=
nil
)
{
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
presenting
=
true
transitionContainer
=
view
transitionContainer
=
view
fromViewController
=
from
fromViewController
=
from
...
@@ -341,7 +341,7 @@ internal extension Motion {
...
@@ -341,7 +341,7 @@ internal extension Motion {
extension
Motion
:
UIViewControllerAnimatedTransitioning
{
extension
Motion
:
UIViewControllerAnimatedTransitioning
{
public
func
animateTransition
(
using
context
:
UIViewControllerContextTransitioning
)
{
public
func
animateTransition
(
using
context
:
UIViewControllerContextTransitioning
)
{
guard
!
t
ransitioning
else
{
return
}
guard
!
isT
ransitioning
else
{
return
}
transitionContext
=
context
transitionContext
=
context
fromViewController
=
fromViewController
??
context
.
viewController
(
forKey
:
.
from
)
fromViewController
=
fromViewController
??
context
.
viewController
(
forKey
:
.
from
)
toViewController
=
toViewController
??
context
.
viewController
(
forKey
:
.
to
)
toViewController
=
toViewController
??
context
.
viewController
(
forKey
:
.
to
)
...
...
Sources/MotionController.swift
View file @
baf1bf57
...
@@ -40,7 +40,7 @@ public class MotionController: NSObject {
...
@@ -40,7 +40,7 @@ public class MotionController: NSObject {
/// progress of the current transition. 0 if no transition is happening
/// progress of the current transition. 0 if no transition is happening
public
internal(set)
var
progress
:
Double
=
0
{
public
internal(set)
var
progress
:
Double
=
0
{
didSet
{
didSet
{
if
t
ransitioning
{
if
isT
ransitioning
{
if
let
progressUpdateObservers
=
progressUpdateObservers
{
if
let
progressUpdateObservers
=
progressUpdateObservers
{
for
observer
in
progressUpdateObservers
{
for
observer
in
progressUpdateObservers
{
observer
.
motionDidUpdateProgress
(
progress
:
progress
)
observer
.
motionDidUpdateProgress
(
progress
:
progress
)
...
@@ -61,12 +61,12 @@ public class MotionController: NSObject {
...
@@ -61,12 +61,12 @@ public class MotionController: NSObject {
}
}
}
}
/// whether or not we are doing a transition
/// whether or not we are doing a transition
public
var
t
ransitioning
:
Bool
{
public
var
isT
ransitioning
:
Bool
{
return
transitionContainer
!=
nil
return
transitionContainer
!=
nil
}
}
/// container we created to hold all animating views, will be a subview of the
/// 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
!
public
internal(set)
var
container
:
UIView
!
/// this is the container supplied by UIKit
/// this is the container supplied by UIKit
...
@@ -98,7 +98,7 @@ public class MotionController: NSObject {
...
@@ -98,7 +98,7 @@ public class MotionController: NSObject {
}
}
}
}
func
displayUpdate
(
_
link
:
CADisplayLink
)
{
func
displayUpdate
(
_
link
:
CADisplayLink
)
{
if
t
ransitioning
,
duration
>
0
,
let
beginTime
=
beginTime
{
if
isT
ransitioning
,
duration
>
0
,
let
beginTime
=
beginTime
{
let
elapsedTime
=
CACurrentMediaTime
()
-
beginTime
let
elapsedTime
=
CACurrentMediaTime
()
-
beginTime
if
elapsedTime
>
duration
{
if
elapsedTime
>
duration
{
...
@@ -138,7 +138,7 @@ public extension MotionController {
...
@@ -138,7 +138,7 @@ public extension MotionController {
- progress: the current progress, must be between -1...1
- progress: the current progress, must be between -1...1
*/
*/
public
func
update
(
progress
:
Double
)
{
public
func
update
(
progress
:
Double
)
{
guard
t
ransitioning
else
{
return
}
guard
isT
ransitioning
else
{
return
}
self
.
beginTime
=
nil
self
.
beginTime
=
nil
self
.
progress
=
max
(
-
1
,
min
(
1
,
progress
))
self
.
progress
=
max
(
-
1
,
min
(
1
,
progress
))
}
}
...
@@ -149,7 +149,7 @@ public extension MotionController {
...
@@ -149,7 +149,7 @@ public extension MotionController {
current state to the **end** state
current state to the **end** state
*/
*/
public
func
end
(
animate
:
Bool
=
true
)
{
public
func
end
(
animate
:
Bool
=
true
)
{
guard
t
ransitioning
else
{
return
}
guard
isT
ransitioning
else
{
return
}
if
!
animate
{
if
!
animate
{
self
.
complete
(
finished
:
true
)
self
.
complete
(
finished
:
true
)
return
return
...
@@ -167,7 +167,7 @@ public extension MotionController {
...
@@ -167,7 +167,7 @@ public extension MotionController {
current state to the **begining** state
current state to the **begining** state
*/
*/
public
func
cancel
(
animate
:
Bool
=
true
)
{
public
func
cancel
(
animate
:
Bool
=
true
)
{
guard
t
ransitioning
else
{
return
}
guard
isT
ransitioning
else
{
return
}
if
!
animate
{
if
!
animate
{
self
.
complete
(
finished
:
false
)
self
.
complete
(
finished
:
false
)
return
return
...
@@ -196,7 +196,7 @@ public extension MotionController {
...
@@ -196,7 +196,7 @@ public extension MotionController {
- view: the view to override to
- view: the view to override to
*/
*/
public
func
apply
(
modifiers
:
[
MotionTransition
],
to
view
:
UIView
)
{
public
func
apply
(
modifiers
:
[
MotionTransition
],
to
view
:
UIView
)
{
guard
t
ransitioning
else
{
return
}
guard
isT
ransitioning
else
{
return
}
let
targetState
=
MotionTargetState
(
modifiers
:
modifiers
)
let
targetState
=
MotionTargetState
(
modifiers
:
modifiers
)
if
let
otherView
=
self
.
context
.
pairedView
(
for
:
view
)
{
if
let
otherView
=
self
.
context
.
pairedView
(
for
:
view
)
{
for
animator
in
self
.
animators
{
for
animator
in
self
.
animators
{
...
@@ -233,7 +233,7 @@ internal extension MotionController {
...
@@ -233,7 +233,7 @@ internal extension MotionController {
/// must have transitionContainer set already
/// must have transitionContainer set already
/// subclass should call context.set(fromViews:toViews) after inserting fromViews & toViews into the container
/// subclass should call context.set(fromViews:toViews) after inserting fromViews & toViews into the container
func
prepareForTransition
()
{
func
prepareForTransition
()
{
guard
t
ransitioning
else
{
fatalError
()
}
guard
isT
ransitioning
else
{
fatalError
()
}
plugins
=
Motion
.
enabledPlugins
.
map
({
return
$0
.
init
()
})
plugins
=
Motion
.
enabledPlugins
.
map
({
return
$0
.
init
()
})
processors
=
[
processors
=
[
IgnoreSubviewModifiersPreprocessor
(),
IgnoreSubviewModifiersPreprocessor
(),
...
@@ -273,14 +273,14 @@ internal extension MotionController {
...
@@ -273,14 +273,14 @@ internal extension MotionController {
}
}
func
processContext
()
{
func
processContext
()
{
guard
t
ransitioning
else
{
fatalError
()
}
guard
isT
ransitioning
else
{
fatalError
()
}
for
processor
in
processors
{
for
processor
in
processors
{
processor
.
process
(
fromViews
:
context
.
fromViews
,
toViews
:
context
.
toViews
)
processor
.
process
(
fromViews
:
context
.
fromViews
,
toViews
:
context
.
toViews
)
}
}
}
}
func
prepareForAnimation
()
{
func
prepareForAnimation
()
{
guard
t
ransitioning
else
{
fatalError
()
}
guard
isT
ransitioning
else
{
fatalError
()
}
animatingViews
=
[([
UIView
],
[
UIView
])]()
animatingViews
=
[([
UIView
],
[
UIView
])]()
for
animator
in
animators
{
for
animator
in
animators
{
let
currentFromViews
=
context
.
fromViews
.
filter
{
(
view
:
UIView
)
->
Bool
in
let
currentFromViews
=
context
.
fromViews
.
filter
{
(
view
:
UIView
)
->
Bool
in
...
@@ -296,7 +296,7 @@ internal extension MotionController {
...
@@ -296,7 +296,7 @@ internal extension MotionController {
/// Actually animate the views
/// Actually animate the views
/// subclass should call `prepareForTransition` & `prepareForAnimation` before calling `animate`
/// subclass should call `prepareForTransition` & `prepareForAnimation` before calling `animate`
func
animate
()
{
func
animate
()
{
guard
t
ransitioning
else
{
fatalError
()
}
guard
isT
ransitioning
else
{
fatalError
()
}
for
(
currentFromViews
,
currentToViews
)
in
animatingViews
{
for
(
currentFromViews
,
currentToViews
)
in
animatingViews
{
// auto hide all animated views
// auto hide all animated views
for
view
in
currentFromViews
{
for
view
in
currentFromViews
{
...
@@ -328,7 +328,7 @@ internal extension MotionController {
...
@@ -328,7 +328,7 @@ internal extension MotionController {
}
}
func
complete
(
after
:
TimeInterval
,
finishing
:
Bool
)
{
func
complete
(
after
:
TimeInterval
,
finishing
:
Bool
)
{
guard
t
ransitioning
else
{
fatalError
()
}
guard
isT
ransitioning
else
{
fatalError
()
}
if
after
<=
0.001
{
if
after
<=
0.001
{
complete
(
finished
:
finishing
)
complete
(
finished
:
finishing
)
return
return
...
@@ -340,7 +340,7 @@ internal extension MotionController {
...
@@ -340,7 +340,7 @@ internal extension MotionController {
}
}
func
complete
(
finished
:
Bool
)
{
func
complete
(
finished
:
Bool
)
{
guard
t
ransitioning
else
{
fatalError
()
}
guard
isT
ransitioning
else
{
fatalError
()
}
for
animator
in
animators
{
for
animator
in
animators
{
animator
.
clean
()
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