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
fcf3d822
Unverified
Commit
fcf3d822
authored
Jun 08, 2017
by
Daniel Dahan
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
initial pass at MotionController rework
parent
19664a2f
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
281 additions
and
146 deletions
+281
-146
Motion.xcodeproj/project.pbxproj
+8
-4
Sources/Motion.swift
+87
-51
Sources/MotionController.swift
+148
-87
Sources/MotionTransitionObserver.swift
+38
-0
Sources/MotionViewController.swift
+0
-4
No files found.
Motion.xcodeproj/project.pbxproj
View file @
fcf3d822
...
@@ -37,7 +37,7 @@
...
@@ -37,7 +37,7 @@
96AEB6A31EE4610F009A3BE0
/* MotionPlugin.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
96AEB67D1EE4610F009A3BE0
/* MotionPlugin.swift */
;
};
96AEB6A31EE4610F009A3BE0
/* MotionPlugin.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
96AEB67D1EE4610F009A3BE0
/* MotionPlugin.swift */
;
};
96AEB6A41EE4610F009A3BE0
/* MotionStringConvertible.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
96AEB67E1EE4610F009A3BE0
/* MotionStringConvertible.swift */
;
};
96AEB6A41EE4610F009A3BE0
/* MotionStringConvertible.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
96AEB67E1EE4610F009A3BE0
/* MotionStringConvertible.swift */
;
};
96AEB6A51EE4610F009A3BE0
/* MotionTargetState.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
96AEB67F1EE4610F009A3BE0
/* MotionTargetState.swift */
;
};
96AEB6A51EE4610F009A3BE0
/* MotionTargetState.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
96AEB67F1EE4610F009A3BE0
/* MotionTargetState.swift */
;
};
96AEB6A61EE4610F009A3BE0
/* Motion
Types.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
96AEB6801EE4610F009A3BE0
/* MotionTypes
.swift */
;
};
96AEB6A61EE4610F009A3BE0
/* Motion
ViewController.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
96AEB6801EE4610F009A3BE0
/* MotionViewController
.swift */
;
};
96AEB6A71EE4610F009A3BE0
/* Lexer.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
96AEB6821EE4610F009A3BE0
/* Lexer.swift */
;
};
96AEB6A71EE4610F009A3BE0
/* Lexer.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
96AEB6821EE4610F009A3BE0
/* Lexer.swift */
;
};
96AEB6A81EE4610F009A3BE0
/* Nodes.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
96AEB6831EE4610F009A3BE0
/* Nodes.swift */
;
};
96AEB6A81EE4610F009A3BE0
/* Nodes.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
96AEB6831EE4610F009A3BE0
/* Nodes.swift */
;
};
96AEB6A91EE4610F009A3BE0
/* Parser.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
96AEB6841EE4610F009A3BE0
/* Parser.swift */
;
};
96AEB6A91EE4610F009A3BE0
/* Parser.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
96AEB6841EE4610F009A3BE0
/* Parser.swift */
;
};
...
@@ -48,6 +48,7 @@
...
@@ -48,6 +48,7 @@
96AEB6AE1EE4610F009A3BE0
/* IgnoreSubviewModifiersPreprocessor.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
96AEB68A1EE4610F009A3BE0
/* IgnoreSubviewModifiersPreprocessor.swift */
;
};
96AEB6AE1EE4610F009A3BE0
/* IgnoreSubviewModifiersPreprocessor.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
96AEB68A1EE4610F009A3BE0
/* IgnoreSubviewModifiersPreprocessor.swift */
;
};
96AEB6AF1EE4610F009A3BE0
/* MatchPreprocessor.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
96AEB68B1EE4610F009A3BE0
/* MatchPreprocessor.swift */
;
};
96AEB6AF1EE4610F009A3BE0
/* MatchPreprocessor.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
96AEB68B1EE4610F009A3BE0
/* MatchPreprocessor.swift */
;
};
96AEB6B01EE4610F009A3BE0
/* SourcePreprocessor.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
96AEB68C1EE4610F009A3BE0
/* SourcePreprocessor.swift */
;
};
96AEB6B01EE4610F009A3BE0
/* SourcePreprocessor.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
96AEB68C1EE4610F009A3BE0
/* SourcePreprocessor.swift */
;
};
96E49A401EEA08F8006D5A93
/* MotionTransitionObserver.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
96E49A3F1EEA08F8006D5A93
/* MotionTransitionObserver.swift */
;
};
/* End PBXBuildFile section */
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
/* Begin PBXFileReference section */
...
@@ -80,7 +81,7 @@
...
@@ -80,7 +81,7 @@
96AEB67D1EE4610F009A3BE0
/* MotionPlugin.swift */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.swift
;
path
=
MotionPlugin.swift
;
sourceTree
=
"<group>"
;
};
96AEB67D1EE4610F009A3BE0
/* MotionPlugin.swift */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.swift
;
path
=
MotionPlugin.swift
;
sourceTree
=
"<group>"
;
};
96AEB67E1EE4610F009A3BE0
/* MotionStringConvertible.swift */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.swift
;
path
=
MotionStringConvertible.swift
;
sourceTree
=
"<group>"
;
};
96AEB67E1EE4610F009A3BE0
/* MotionStringConvertible.swift */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.swift
;
path
=
MotionStringConvertible.swift
;
sourceTree
=
"<group>"
;
};
96AEB67F1EE4610F009A3BE0
/* MotionTargetState.swift */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.swift
;
path
=
MotionTargetState.swift
;
sourceTree
=
"<group>"
;
};
96AEB67F1EE4610F009A3BE0
/* MotionTargetState.swift */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.swift
;
path
=
MotionTargetState.swift
;
sourceTree
=
"<group>"
;
};
96AEB6801EE4610F009A3BE0
/* Motion
Types.swift */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.swift
;
path
=
MotionTypes
.swift
;
sourceTree
=
"<group>"
;
};
96AEB6801EE4610F009A3BE0
/* Motion
ViewController.swift */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.swift
;
path
=
MotionViewController
.swift
;
sourceTree
=
"<group>"
;
};
96AEB6821EE4610F009A3BE0
/* Lexer.swift */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.swift
;
path
=
Lexer.swift
;
sourceTree
=
"<group>"
;
};
96AEB6821EE4610F009A3BE0
/* Lexer.swift */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.swift
;
path
=
Lexer.swift
;
sourceTree
=
"<group>"
;
};
96AEB6831EE4610F009A3BE0
/* Nodes.swift */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.swift
;
path
=
Nodes.swift
;
sourceTree
=
"<group>"
;
};
96AEB6831EE4610F009A3BE0
/* Nodes.swift */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.swift
;
path
=
Nodes.swift
;
sourceTree
=
"<group>"
;
};
96AEB6841EE4610F009A3BE0
/* Parser.swift */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.swift
;
path
=
Parser.swift
;
sourceTree
=
"<group>"
;
};
96AEB6841EE4610F009A3BE0
/* Parser.swift */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.swift
;
path
=
Parser.swift
;
sourceTree
=
"<group>"
;
};
...
@@ -95,6 +96,7 @@
...
@@ -95,6 +96,7 @@
96C98DDD1E424B9000B22906
/* Info.plist */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
text.plist.xml
;
path
=
Info.plist
;
sourceTree
=
"<group>"
;
};
96C98DDD1E424B9000B22906
/* Info.plist */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
text.plist.xml
;
path
=
Info.plist
;
sourceTree
=
"<group>"
;
};
96C98DE21E43809D00B22906
/* LICENSE */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
text
;
path
=
LICENSE
;
sourceTree
=
"<group>"
;
};
96C98DE21E43809D00B22906
/* LICENSE */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
text
;
path
=
LICENSE
;
sourceTree
=
"<group>"
;
};
96C98DED1E438A5700B22906
/* Motion.h */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.c.h
;
path
=
Motion.h
;
sourceTree
=
"<group>"
;
};
96C98DED1E438A5700B22906
/* Motion.h */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.c.h
;
path
=
Motion.h
;
sourceTree
=
"<group>"
;
};
96E49A3F1EEA08F8006D5A93
/* MotionTransitionObserver.swift */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.swift
;
path
=
MotionTransitionObserver.swift
;
sourceTree
=
"<group>"
;
};
/* End PBXFileReference section */
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
/* Begin PBXFrameworksBuildPhase section */
...
@@ -207,7 +209,8 @@
...
@@ -207,7 +209,8 @@
96AEB67D1EE4610F009A3BE0
/* MotionPlugin.swift */
,
96AEB67D1EE4610F009A3BE0
/* MotionPlugin.swift */
,
96AEB67E1EE4610F009A3BE0
/* MotionStringConvertible.swift */
,
96AEB67E1EE4610F009A3BE0
/* MotionStringConvertible.swift */
,
96AEB67F1EE4610F009A3BE0
/* MotionTargetState.swift */
,
96AEB67F1EE4610F009A3BE0
/* MotionTargetState.swift */
,
96AEB6801EE4610F009A3BE0
/* MotionTypes.swift */
,
96AEB6801EE4610F009A3BE0
/* MotionViewController.swift */
,
96E49A3F1EEA08F8006D5A93
/* MotionTransitionObserver.swift */
,
96AEB6811EE4610F009A3BE0
/* Parser */
,
96AEB6811EE4610F009A3BE0
/* Parser */
,
96AEB6861EE4610F009A3BE0
/* Preprocessors */
,
96AEB6861EE4610F009A3BE0
/* Preprocessors */
,
);
);
...
@@ -308,9 +311,10 @@
...
@@ -308,9 +311,10 @@
96AEB6961EE4610F009A3BE0
/* Motion+CAMediaTimingFunction.swift in Sources */
,
96AEB6961EE4610F009A3BE0
/* Motion+CAMediaTimingFunction.swift in Sources */
,
96AEB6941EE4610F009A3BE0
/* Motion+Array.swift in Sources */
,
96AEB6941EE4610F009A3BE0
/* Motion+Array.swift in Sources */
,
96AEB6951EE4610F009A3BE0
/* Motion+CALayer.swift in Sources */
,
96AEB6951EE4610F009A3BE0
/* Motion+CALayer.swift in Sources */
,
96AEB6A61EE4610F009A3BE0
/* Motion
Types
.swift in Sources */
,
96AEB6A61EE4610F009A3BE0
/* Motion
ViewController
.swift in Sources */
,
96AEB68E1EE4610F009A3BE0
/* MotionCoreAnimationViewContext.swift in Sources */
,
96AEB68E1EE4610F009A3BE0
/* MotionCoreAnimationViewContext.swift in Sources */
,
96AEB6921EE4610F009A3BE0
/* MotionDebugView.swift in Sources */
,
96AEB6921EE4610F009A3BE0
/* MotionDebugView.swift in Sources */
,
96E49A401EEA08F8006D5A93
/* MotionTransitionObserver.swift in Sources */
,
96AEB6A01EE4610F009A3BE0
/* MotionIndependentController.swift in Sources */
,
96AEB6A01EE4610F009A3BE0
/* MotionIndependentController.swift in Sources */
,
96AEB6AA1EE4610F009A3BE0
/* Regex.swift in Sources */
,
96AEB6AA1EE4610F009A3BE0
/* Regex.swift in Sources */
,
96AEB6901EE4610F009A3BE0
/* MotionViewPropertyViewContext.swift in Sources */
,
96AEB6901EE4610F009A3BE0
/* MotionViewPropertyViewContext.swift in Sources */
,
...
...
Sources/Motion.swift
View file @
fcf3d822
...
@@ -58,11 +58,13 @@ public class Motion: MotionController {
...
@@ -58,11 +58,13 @@ public class Motion: MotionController {
public
internal(set)
var
isPresenting
=
true
public
internal(set)
var
isPresenting
=
true
/// Progress of the current transition, 0 if a transition is not happening.
/// Progress of the current transition, 0 if a transition is not happening.
public
override
var
progress
:
Double
{
public
override
var
elapsedTime
:
TimeInterval
{
didSet
{
didSet
{
if
isTransitioning
{
guard
isTransitioning
else
{
transitionContext
?
.
updateInteractiveTransition
(
CGFloat
(
progress
))
return
}
}
transitionContext
?
.
updateInteractiveTransition
(
CGFloat
(
elapsedTime
))
}
}
}
}
...
@@ -155,7 +157,7 @@ public extension Motion {
...
@@ -155,7 +157,7 @@ public extension Motion {
}
}
}
}
internal
extension
Motion
{
fileprivate
extension
Motion
{
/// Starts the transition animation.
/// Starts the transition animation.
func
start
()
{
func
start
()
{
guard
isTransitioning
else
{
guard
isTransitioning
else
{
...
@@ -165,51 +167,25 @@ internal extension Motion {
...
@@ -165,51 +167,25 @@ internal extension Motion {
prepareViewControllers
()
prepareViewControllers
()
prepareSnapshotView
()
prepareSnapshotView
()
prepareForTransition
()
prepareForTransition
()
prepare
Motion
Context
()
prepareContext
()
prepareToView
()
prepareToView
()
prepareViewHierarchy
()
prepareViewHierarchy
()
processContext
()
processContext
()
prepareForAnimation
()
prepareForAnimation
()
processForAnimation
()
context
.
hide
(
view
:
toView
)
#if os(tvOS)
animate
()
#else
if
isNavigationController
{
// When animating within navigationController, we have to dispatch later into the main queue.
// otherwise snapshots will be pure white. Possibly a bug with UIKit
DispatchQueue
.
main
.
async
{
[
weak
self
]
in
self
?
.
animate
()
}
}
else
{
animate
()
}
#endif
}
}
}
internal
extension
Motion
{
override
func
animate
()
{
override
func
animate
()
{
context
.
unhide
(
view
:
toView
)
context
.
unhide
(
view
:
toView
)
if
let
containerBackgroundColor
=
containerBackgroundColor
{
updateContainerBackgroundColor
()
container
.
backgroundColor
=
containerBackgroundColor
updateInsertOrder
()
}
else
if
!
toOverFullScreen
&&
!
fromOverFullScreen
{
container
.
backgroundColor
=
toView
.
backgroundColor
}
if
fromOverFullScreen
{
insertToViewFirst
=
true
}
for
animator
in
animators
{
if
let
animator
=
animator
as?
MotionHasInsertOrder
{
animator
.
insertToViewFirst
=
insertToViewFirst
}
}
super
.
animate
()
super
.
animate
()
fullScreenSnapshot
!.
removeFromSuperview
()
fullScreenSnapshot
?
.
removeFromSuperview
()
}
}
override
func
complete
(
finished
:
Bool
)
{
override
func
complete
(
finished
:
Bool
)
{
...
@@ -344,7 +320,7 @@ fileprivate extension Motion {
...
@@ -344,7 +320,7 @@ fileprivate extension Motion {
}
}
/// Prepares the MotionContext instance.
/// Prepares the MotionContext instance.
func
prepare
Motion
Context
()
{
func
prepareContext
()
{
context
.
loadViewAlpha
(
rootView
:
toView
)
context
.
loadViewAlpha
(
rootView
:
toView
)
context
.
loadViewAlpha
(
rootView
:
fromView
)
context
.
loadViewAlpha
(
rootView
:
fromView
)
container
.
addSubview
(
toView
)
container
.
addSubview
(
toView
)
...
@@ -370,6 +346,52 @@ internal extension Motion {
...
@@ -370,6 +346,52 @@ internal extension Motion {
super
.
prepareForTransition
()
super
.
prepareForTransition
()
insert
(
preprocessor
:
DefaultAnimationPreprocessor
(
motion
:
self
),
before
:
DurationPreprocessor
.
self
)
insert
(
preprocessor
:
DefaultAnimationPreprocessor
(
motion
:
self
),
before
:
DurationPreprocessor
.
self
)
}
}
override
func
prepareForAnimation
()
{
super
.
prepareForAnimation
()
context
.
hide
(
view
:
toView
)
}
}
fileprivate
extension
Motion
{
/// Processes the animations.
func
processForAnimation
()
{
#if os(tvOS)
animate
()
#else
if
isNavigationController
{
// When animating within navigationController, we have to dispatch later into the main queue.
// otherwise snapshots will be pure white. Possibly a bug with UIKit
DispatchQueue
.
main
.
async
{
[
weak
self
]
in
self
?
.
animate
()
}
}
else
{
animate
()
}
#endif
}
}
fileprivate
extension
Motion
{
/// Updates the container background color.
func
updateContainerBackgroundColor
()
{
if
let
v
=
containerBackgroundColor
{
container
.
backgroundColor
=
v
}
else
if
!
toOverFullScreen
&&
!
fromOverFullScreen
{
container
.
backgroundColor
=
toView
.
backgroundColor
}
}
/// Updates the insertToViewFirst boolean for animators.
func
updateInsertOrder
()
{
if
fromOverFullScreen
{
insertToViewFirst
=
true
}
for
v
in
animators
{
(
v
as?
MotionHasInsertOrder
)?
.
insertToViewFirst
=
insertToViewFirst
}
}
}
}
internal
extension
Motion
{
internal
extension
Motion
{
...
@@ -418,23 +440,31 @@ internal extension Motion {
...
@@ -418,23 +440,31 @@ internal extension Motion {
}
}
}
}
// MARK: UIKit Protocol Conformance
/*****************************
* UIKit protocol extensions *
*****************************/
extension
Motion
:
UIViewControllerAnimatedTransitioning
{
extension
Motion
:
UIViewControllerAnimatedTransitioning
{
/**
The animation method that is used to coordinate the transition.
- Parameter using transitionContext: A UIViewControllerContextTransitioning.
*/
public
func
animateTransition
(
using
context
:
UIViewControllerContextTransitioning
)
{
public
func
animateTransition
(
using
context
:
UIViewControllerContextTransitioning
)
{
guard
!
isTransitioning
else
{
return
}
guard
!
isTransitioning
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
)
transitionContainer
=
context
.
containerView
transitionContainer
=
context
.
containerView
start
()
start
()
}
}
/**
Returns the transition duration time interval.
- Parameter using transitionContext: An optional UIViewControllerContextTransitioning.
- Returns: A TimeInterval that is the total animation time including delays.
*/
public
func
transitionDuration
(
using
transitionContext
:
UIViewControllerContextTransitioning
?)
->
TimeInterval
{
public
func
transitionDuration
(
using
transitionContext
:
UIViewControllerContextTransitioning
?)
->
TimeInterval
{
return
0.375
// doesn't matter, real duration will be calculated later
return
0
// Will be updated dynamically.
}
}
public
func
animationEnded
(
_
transitionCompleted
:
Bool
)
{
public
func
animationEnded
(
_
transitionCompleted
:
Bool
)
{
...
@@ -442,11 +472,14 @@ extension Motion: UIViewControllerAnimatedTransitioning {
...
@@ -442,11 +472,14 @@ extension Motion: UIViewControllerAnimatedTransitioning {
}
}
}
}
extension
Motion
:
UIViewControllerTransitioningDelegate
{
extension
Motion
{
var
interactiveTransitioning
:
UIViewControllerInteractiveTransitioning
?
{
/// A reference to the interactive transitioning.
return
forceNonInteractive
?
nil
:
self
fileprivate
var
interactiveTransitioning
:
UIViewControllerInteractiveTransitioning
?
{
return
self
}
}
}
extension
Motion
:
UIViewControllerTransitioningDelegate
{
public
func
animationController
(
forPresented
presented
:
UIViewController
,
presenting
:
UIViewController
,
source
:
UIViewController
)
->
UIViewControllerAnimatedTransitioning
?
{
public
func
animationController
(
forPresented
presented
:
UIViewController
,
presenting
:
UIViewController
,
source
:
UIViewController
)
->
UIViewControllerAnimatedTransitioning
?
{
self
.
isPresenting
=
true
self
.
isPresenting
=
true
self
.
fromViewController
=
fromViewController
??
presenting
self
.
fromViewController
=
fromViewController
??
presenting
...
@@ -480,7 +513,7 @@ extension Motion: UIViewControllerInteractiveTransitioning {
...
@@ -480,7 +513,7 @@ extension Motion: UIViewControllerInteractiveTransitioning {
extension
Motion
:
UINavigationControllerDelegate
{
extension
Motion
:
UINavigationControllerDelegate
{
public
func
navigationController
(
_
navigationController
:
UINavigationController
,
animationControllerFor
operation
:
UINavigationControllerOperation
,
from
fromVC
:
UIViewController
,
to
toVC
:
UIViewController
)
->
UIViewControllerAnimatedTransitioning
?
{
public
func
navigationController
(
_
navigationController
:
UINavigationController
,
animationControllerFor
operation
:
UINavigationControllerOperation
,
from
fromVC
:
UIViewController
,
to
toVC
:
UIViewController
)
->
UIViewControllerAnimatedTransitioning
?
{
self
.
isPresenting
=
operation
==
.
push
self
.
isPresenting
=
.
push
==
operation
self
.
fromViewController
=
fromViewController
??
fromVC
self
.
fromViewController
=
fromViewController
??
fromVC
self
.
toViewController
=
toViewController
??
toVC
self
.
toViewController
=
toViewController
??
toVC
self
.
isNavigationController
=
true
self
.
isNavigationController
=
true
...
@@ -503,12 +536,15 @@ extension Motion: UITabBarControllerDelegate {
...
@@ -503,12 +536,15 @@ extension Motion: UITabBarControllerDelegate {
public
func
tabBarController
(
_
tabBarController
:
UITabBarController
,
animationControllerForTransitionFrom
fromVC
:
UIViewController
,
to
toVC
:
UIViewController
)
->
UIViewControllerAnimatedTransitioning
?
{
public
func
tabBarController
(
_
tabBarController
:
UITabBarController
,
animationControllerForTransitionFrom
fromVC
:
UIViewController
,
to
toVC
:
UIViewController
)
->
UIViewControllerAnimatedTransitioning
?
{
isAnimating
=
true
isAnimating
=
true
let
fromVCIndex
=
tabBarController
.
childViewControllers
.
index
(
of
:
fromVC
)
!
let
fromVCIndex
=
tabBarController
.
childViewControllers
.
index
(
of
:
fromVC
)
!
let
toVCIndex
=
tabBarController
.
childViewControllers
.
index
(
of
:
toVC
)
!
let
toVCIndex
=
tabBarController
.
childViewControllers
.
index
(
of
:
toVC
)
!
self
.
isPresenting
=
toVCIndex
>
fromVCIndex
self
.
isPresenting
=
toVCIndex
>
fromVCIndex
self
.
fromViewController
=
fromViewController
??
fromVC
self
.
fromViewController
=
fromViewController
??
fromVC
self
.
toViewController
=
toViewController
??
toVC
self
.
toViewController
=
toViewController
??
toVC
self
.
isTabBarController
=
true
self
.
isTabBarController
=
true
return
self
return
self
}
}
}
}
...
...
Sources/MotionController.swift
View file @
fcf3d822
...
@@ -28,107 +28,168 @@
...
@@ -28,107 +28,168 @@
import
UIKit
import
UIKit
/// Base class for managing a Motion transition
public
class
MotionController
:
NSObject
{
public
class
MotionController
:
NSObject
{
// MARK: Properties
/// A reference to the MotionContext.
/// context object holding transition informations
public
internal(set)
var
context
:
MotionContext
!
public
internal(set)
var
context
:
MotionContext
!
/// whether or not we are handling transition interactively
public
var
interactive
:
Bool
{
/// A boolean indicating whether the transition interactive or not.
return
displayLink
==
nil
public
var
isInteractive
:
Bool
{
return
nil
==
displayLink
}
}
/// progress of the current transition. 0 if no transition is happening
public
internal(set)
var
progress
:
Double
=
0
{
/// Progress of the current transition. 0 if no transition is happening.
public
internal(set)
var
elapsedTime
:
TimeInterval
=
0
{
didSet
{
didSet
{
if
isTransitioning
{
guard
isTransitioning
else
{
if
let
progressUpdateObservers
=
progressUpdateObservers
{
return
for
observer
in
progressUpdateObservers
{
observer
.
motionDidUpdateProgress
(
progress
:
progress
)
}
}
}
let
elapsedTime
=
progress
*
totalDuration
updateTransitionObservers
()
if
interactive
{
for
animator
in
animators
{
guard
isInteractive
else
{
animator
.
seek
(
to
:
elapsedTime
)
updatePlugins
()
}
return
}
else
{
for
plugin
in
plugins
where
plugin
.
requirePerFrameCallback
{
plugin
.
seek
(
to
:
elapsedTime
)
}
}
}
}
updateAnimators
()
}
}
}
}
/// whether or not we are doing a transition
/// A boolean indicating whether a transition is active.
public
var
isTransitioning
:
Bool
{
public
var
isTransitioning
:
Bool
{
return
transitionContainer
!=
nil
return
nil
!=
transitionContainer
}
}
/// container we created to hold all animating views, will be a subview of the
/**
/// transitionContainer when isTransitioning
A view container used to hold all the animating views during a
transition.
*/
public
internal(set)
var
container
:
UIView
!
public
internal(set)
var
container
:
UIView
!
/// this is the container supplied by UIKit
/// UIKit's supplied transition container.
internal
var
transitionContainer
:
UIView
!
internal
var
transitionContainer
:
UIView
!
/// An optional completion callback.
internal
var
completionCallback
:
((
Bool
)
->
Void
)?
internal
var
completionCallback
:
((
Bool
)
->
Void
)?
/// Binds the render cycle to the transition animation.
internal
var
displayLink
:
CADisplayLink
?
internal
var
displayLink
:
CADisplayLink
?
internal
var
progressUpdateObservers
:
[
MotionProgressUpdateObserver
]?
/// max duration needed by the default animator and plugins
/// An Array of observers that are updated during a transition.
public
internal(set)
var
totalDuration
:
TimeInterval
=
0.0
internal
var
transitionObservers
:
[
MotionTransitionObserver
]?
/// Max duration used by MotionAnimators and MotionPlugins.
public
internal(set)
var
totalDuration
:
TimeInterval
=
0
/// current animation complete duration.
/// The currently running animation duration.
/// (differs from totalDuration because this one could be the duration for finishing interactive transition)
internal
var
currentAnimationDuration
:
TimeInterval
=
0
internal
var
duration
:
TimeInterval
=
0.0
/// The start time of the animation.
internal
var
beginTime
:
TimeInterval
?
{
internal
var
beginTime
:
TimeInterval
?
{
didSet
{
didSet
{
if
beginTime
!=
nil
{
guard
nil
!=
beginTime
else
{
if
displayLink
==
nil
{
displayLink
=
CADisplayLink
(
target
:
self
,
selector
:
#selector(
displayUpdate(_:)
)
)
displayLink
!.
add
(
to
:
RunLoop
.
main
,
forMode
:
RunLoopMode
(
rawValue
:
RunLoopMode
.
commonModes
.
rawValue
))
}
}
else
{
displayLink
?
.
isPaused
=
true
displayLink
?
.
isPaused
=
true
displayLink
?
.
remove
(
from
:
RunLoop
.
main
,
forMode
:
RunLoopMode
(
rawValue
:
RunLoopMode
.
commonModes
.
rawValue
))
displayLink
?
.
remove
(
from
:
RunLoop
.
main
,
forMode
:
RunLoopMode
(
rawValue
:
RunLoopMode
.
commonModes
.
rawValue
))
displayLink
=
nil
displayLink
=
nil
return
}
}
}
}
func
displayUpdate
(
_
link
:
CADisplayLink
)
{
if
isTransitioning
,
duration
>
0
,
let
beginTime
=
beginTime
{
let
elapsedTime
=
CACurrentMediaTime
()
-
beginTime
if
elapsedTime
>
duration
{
guard
nil
==
displayLink
else
{
progress
=
finishing
?
1
:
0
return
self
.
beginTime
=
nil
complete
(
finished
:
finishing
)
}
else
{
var
completed
=
elapsedTime
/
totalDuration
if
!
finishing
{
completed
=
1
-
completed
}
completed
=
max
(
0
,
min
(
1
,
completed
))
progress
=
completed
}
}
displayLink
=
CADisplayLink
(
target
:
self
,
selector
:
#selector(
handleDisplayLink(_:)
)
)
displayLink
?
.
add
(
to
:
RunLoop
.
main
,
forMode
:
RunLoopMode
(
rawValue
:
RunLoopMode
.
commonModes
.
rawValue
))
}
}
}
}
internal
var
finishing
:
Bool
=
true
/// A boolean indicating if the transition has finished.
internal
var
isFinished
=
true
/// An Array of MotionPreprocessors used during a transition.
internal
var
processors
:
[
MotionPreprocessor
]
!
internal
var
processors
:
[
MotionPreprocessor
]
!
/// An Array of MotionAnimators used during a transition.
internal
var
animators
:
[
MotionAnimator
]
!
internal
var
animators
:
[
MotionAnimator
]
!
/// An Array of MotionPlugins used during a transition.
internal
var
plugins
:
[
MotionPlugin
]
!
internal
var
plugins
:
[
MotionPlugin
]
!
internal
var
animatingViews
:
[(
fromViews
:
[
UIView
],
toViews
:
[
UIView
])]
!
/// The matching from-views to to-views based on the motionIdentifier value.
internal
var
transitionPairs
:
[(
fromViews
:
[
UIView
],
toViews
:
[
UIView
])]
!
internal
static
var
enabledPlugins
:
[
MotionPlugin
.
Type
]
=
[]
/// Plugins that are enabled during the transition.
internal
static
var
enabledPlugins
=
[
MotionPlugin
.
Type
]()
/// Initializer.
internal
override
init
()
{}
internal
override
init
()
{}
}
}
fileprivate
extension
MotionController
{
/// Updates the transition observers.
func
updateTransitionObservers
()
{
guard
let
observers
=
transitionObservers
else
{
return
}
for
v
in
observers
{
v
.
motion
(
transitionObserver
:
v
,
didUpdateWith
:
elapsedTime
)
}
}
/// Updates the animators.
func
updateAnimators
()
{
let
v
=
elapsedTime
*
totalDuration
for
a
in
animators
{
a
.
seek
(
to
:
v
)
}
}
/// Updates the plugins.
func
updatePlugins
()
{
let
v
=
elapsedTime
*
totalDuration
for
p
in
plugins
where
p
.
requirePerFrameCallback
{
p
.
seek
(
to
:
v
)
}
}
}
fileprivate
extension
MotionController
{
@objc
func
handleDisplayLink
(
_
link
:
CADisplayLink
)
{
guard
isTransitioning
else
{
return
}
guard
0
<
currentAnimationDuration
else
{
return
}
guard
let
t
=
beginTime
else
{
return
}
let
cTime
=
CACurrentMediaTime
()
-
t
if
cTime
>
currentAnimationDuration
{
elapsedTime
=
isFinished
?
1
:
0
beginTime
=
nil
complete
(
isFinished
:
isFinished
)
}
else
{
var
eTime
=
cTime
/
totalDuration
if
!
isFinished
{
eTime
=
1
-
eTime
}
elapsedTime
=
max
(
0
,
min
(
1
,
eTime
))
}
}
}
public
extension
MotionController
{
public
extension
MotionController
{
// MARK: Interactive Transition
// MARK: Interactive Transition
...
@@ -140,7 +201,7 @@ public extension MotionController {
...
@@ -140,7 +201,7 @@ public extension MotionController {
public
func
update
(
progress
:
Double
)
{
public
func
update
(
progress
:
Double
)
{
guard
isTransitioning
else
{
return
}
guard
isTransitioning
else
{
return
}
self
.
beginTime
=
nil
self
.
beginTime
=
nil
self
.
progress
=
max
(
-
1
,
min
(
1
,
progress
))
self
.
elapsedTime
=
max
(
-
1
,
min
(
1
,
progress
))
}
}
/**
/**
...
@@ -151,14 +212,14 @@ public extension MotionController {
...
@@ -151,14 +212,14 @@ public extension MotionController {
public
func
end
(
animate
:
Bool
=
true
)
{
public
func
end
(
animate
:
Bool
=
true
)
{
guard
isTransitioning
else
{
return
}
guard
isTransitioning
else
{
return
}
if
!
animate
{
if
!
animate
{
self
.
complete
(
f
inished
:
true
)
self
.
complete
(
isF
inished
:
true
)
return
return
}
}
var
maxTime
:
TimeInterval
=
0
var
maxTime
:
TimeInterval
=
0
for
animator
in
self
.
animators
{
for
animator
in
self
.
animators
{
maxTime
=
max
(
maxTime
,
animator
.
resume
(
at
:
self
.
progress
*
self
.
totalDuration
,
isReversed
:
false
))
maxTime
=
max
(
maxTime
,
animator
.
resume
(
at
:
self
.
elapsedTime
*
self
.
totalDuration
,
isReversed
:
false
))
}
}
self
.
complete
(
after
:
maxTime
,
finishing
:
true
)
self
.
complete
(
after
:
maxTime
,
isFinished
:
true
)
}
}
/**
/**
...
@@ -169,18 +230,18 @@ public extension MotionController {
...
@@ -169,18 +230,18 @@ public extension MotionController {
public
func
cancel
(
animate
:
Bool
=
true
)
{
public
func
cancel
(
animate
:
Bool
=
true
)
{
guard
isTransitioning
else
{
return
}
guard
isTransitioning
else
{
return
}
if
!
animate
{
if
!
animate
{
self
.
complete
(
f
inished
:
false
)
self
.
complete
(
isF
inished
:
false
)
return
return
}
}
var
maxTime
:
TimeInterval
=
0
var
maxTime
:
TimeInterval
=
0
for
animator
in
self
.
animators
{
for
animator
in
self
.
animators
{
var
adjustedProgress
=
self
.
progress
var
adjustedProgress
=
self
.
elapsedTime
if
adjustedProgress
<
0
{
if
adjustedProgress
<
0
{
adjustedProgress
=
-
adjustedProgress
adjustedProgress
=
-
adjustedProgress
}
}
maxTime
=
max
(
maxTime
,
animator
.
resume
(
at
:
adjustedProgress
*
self
.
totalDuration
,
isReversed
:
true
))
maxTime
=
max
(
maxTime
,
animator
.
resume
(
at
:
adjustedProgress
*
self
.
totalDuration
,
isReversed
:
true
))
}
}
self
.
complete
(
after
:
maxTime
,
finishing
:
false
)
self
.
complete
(
after
:
maxTime
,
isFinished
:
false
)
}
}
/**
/**
...
@@ -219,11 +280,11 @@ public extension MotionController {
...
@@ -219,11 +280,11 @@ public extension MotionController {
- Parameters:
- Parameters:
- observer: the observer
- observer: the observer
*/
*/
func
observeForProgressUpdate
(
observer
:
Motion
ProgressUpdate
Observer
)
{
func
observeForProgressUpdate
(
observer
:
Motion
Transition
Observer
)
{
if
progressUpdate
Observers
==
nil
{
if
transition
Observers
==
nil
{
progressUpdate
Observers
=
[]
transition
Observers
=
[]
}
}
progressUpdate
Observers
!.
append
(
observer
)
transition
Observers
!.
append
(
observer
)
}
}
}
}
...
@@ -283,7 +344,7 @@ internal extension MotionController {
...
@@ -283,7 +344,7 @@ internal extension MotionController {
func
prepareForAnimation
()
{
func
prepareForAnimation
()
{
guard
isTransitioning
else
{
fatalError
()
}
guard
isTransitioning
else
{
fatalError
()
}
animatingView
s
=
[([
UIView
],
[
UIView
])]()
transitionPair
s
=
[([
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
return
animator
.
canAnimate
(
view
:
view
,
isAppearing
:
false
)
return
animator
.
canAnimate
(
view
:
view
,
isAppearing
:
false
)
...
@@ -291,7 +352,7 @@ internal extension MotionController {
...
@@ -291,7 +352,7 @@ internal extension MotionController {
let
currentToViews
=
context
.
toViews
.
filter
{
(
view
:
UIView
)
->
Bool
in
let
currentToViews
=
context
.
toViews
.
filter
{
(
view
:
UIView
)
->
Bool
in
return
animator
.
canAnimate
(
view
:
view
,
isAppearing
:
true
)
return
animator
.
canAnimate
(
view
:
view
,
isAppearing
:
true
)
}
}
animatingView
s
.
append
((
currentFromViews
,
currentToViews
))
transitionPair
s
.
append
((
currentFromViews
,
currentToViews
))
}
}
}
}
...
@@ -299,7 +360,7 @@ internal extension MotionController {
...
@@ -299,7 +360,7 @@ internal extension MotionController {
/// subclass should call `prepareForTransition` & `prepareForAnimation` before calling `animate`
/// subclass should call `prepareForTransition` & `prepareForAnimation` before calling `animate`
func
animate
()
{
func
animate
()
{
guard
isTransitioning
else
{
fatalError
()
}
guard
isTransitioning
else
{
fatalError
()
}
for
(
currentFromViews
,
currentToViews
)
in
animatingView
s
{
for
(
currentFromViews
,
currentToViews
)
in
transitionPair
s
{
// auto hide all animated views
// auto hide all animated views
for
view
in
currentFromViews
{
for
view
in
currentFromViews
{
context
.
hide
(
view
:
view
)
context
.
hide
(
view
:
view
)
...
@@ -312,8 +373,8 @@ internal extension MotionController {
...
@@ -312,8 +373,8 @@ internal extension MotionController {
var
totalDuration
:
TimeInterval
=
0
var
totalDuration
:
TimeInterval
=
0
var
animatorWantsInteractive
=
false
var
animatorWantsInteractive
=
false
for
(
i
,
animator
)
in
animators
.
enumerated
()
{
for
(
i
,
animator
)
in
animators
.
enumerated
()
{
let
duration
=
animator
.
animate
(
fromViews
:
animatingView
s
[
i
]
.
0
,
let
duration
=
animator
.
animate
(
fromViews
:
transitionPair
s
[
i
]
.
0
,
toViews
:
animatingView
s
[
i
]
.
1
)
toViews
:
transitionPair
s
[
i
]
.
1
)
if
duration
==
.
infinity
{
if
duration
==
.
infinity
{
animatorWantsInteractive
=
true
animatorWantsInteractive
=
true
}
else
{
}
else
{
...
@@ -325,23 +386,23 @@ internal extension MotionController {
...
@@ -325,23 +386,23 @@ internal extension MotionController {
if
animatorWantsInteractive
{
if
animatorWantsInteractive
{
update
(
progress
:
0
)
update
(
progress
:
0
)
}
else
{
}
else
{
complete
(
after
:
totalDuration
,
finishing
:
true
)
complete
(
after
:
totalDuration
,
isFinished
:
true
)
}
}
}
}
func
complete
(
after
:
TimeInterval
,
finishing
:
Bool
)
{
func
complete
(
after
:
TimeInterval
,
isFinished
:
Bool
)
{
guard
isTransitioning
else
{
fatalError
()
}
guard
isTransitioning
else
{
fatalError
()
}
if
after
<=
0.001
{
if
after
<=
0.001
{
complete
(
finished
:
finishing
)
complete
(
isFinished
:
isFinished
)
return
return
}
}
let
elapsedTime
=
(
finishing
?
progress
:
1
-
progress
)
*
totalDuration
let
v
=
(
isFinished
?
elapsedTime
:
1
-
elapsedTime
)
*
totalDuration
self
.
finishing
=
finishing
self
.
isFinished
=
isFinished
self
.
duration
=
after
+
elapsedTime
self
.
currentAnimationDuration
=
after
+
v
self
.
beginTime
=
CACurrentMediaTime
()
-
elapsedTime
self
.
beginTime
=
CACurrentMediaTime
()
-
v
}
}
func
complete
(
f
inished
:
Bool
)
{
func
complete
(
isF
inished
:
Bool
)
{
guard
isTransitioning
else
{
fatalError
()
}
guard
isTransitioning
else
{
fatalError
()
}
for
animator
in
animators
{
for
animator
in
animators
{
animator
.
clean
()
animator
.
clean
()
...
@@ -351,8 +412,8 @@ internal extension MotionController {
...
@@ -351,8 +412,8 @@ internal extension MotionController {
let
completion
=
completionCallback
let
completion
=
completionCallback
animatingView
s
=
nil
transitionPair
s
=
nil
progressUpdate
Observers
=
nil
transition
Observers
=
nil
transitionContainer
=
nil
transitionContainer
=
nil
completionCallback
=
nil
completionCallback
=
nil
container
=
nil
container
=
nil
...
@@ -361,10 +422,10 @@ internal extension MotionController {
...
@@ -361,10 +422,10 @@ internal extension MotionController {
plugins
=
nil
plugins
=
nil
context
=
nil
context
=
nil
beginTime
=
nil
beginTime
=
nil
progress
=
0
elapsedTime
=
0
totalDuration
=
0
totalDuration
=
0
completion
?(
f
inished
)
completion
?(
isF
inished
)
}
}
}
}
...
...
Sources/MotionTransitionObserver.swift
0 → 100644
View file @
fcf3d822
/*
* The MIT License (MIT)
*
* Copyright (C) 2017, Daniel Dahan and CosmicMind, Inc. <http://cosmicmind.com>.
* All rights reserved.
*
* Original Inspiration & Author
* Copyright (c) 2016 Luke Zhao <me@lkzhao.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
import
Foundation
public
protocol
MotionTransitionObserver
{
/**
Executed when the elapsed time changes during a transition.
- Parameter transitionObserver: A MotionTransitionObserver.
- Parameter didUpdateWith elapsedTime: A TimeInterval.
*/
func
motion
(
transitionObserver
:
MotionTransitionObserver
,
didUpdateWith
elapsedTime
:
TimeInterval
)
}
Sources/Motion
Types
.swift
→
Sources/Motion
ViewController
.swift
View file @
fcf3d822
...
@@ -28,10 +28,6 @@
...
@@ -28,10 +28,6 @@
import
UIKit
import
UIKit
public
protocol
MotionProgressUpdateObserver
{
func
motionDidUpdateProgress
(
progress
:
Double
)
}
@objc(MotionViewControllerDelegate)
@objc(MotionViewControllerDelegate)
public
protocol
MotionViewControllerDelegate
{
public
protocol
MotionViewControllerDelegate
{
@objc
@objc
...
...
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