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
d21da35d
Unverified
Commit
d21da35d
authored
Jun 09, 2017
by
Daniel Dahan
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
reworked MotionContext
parent
aa31695e
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
235 additions
and
114 deletions
+235
-114
Sources/MotionContext.swift
+232
-111
Sources/MotionController.swift
+1
-1
Sources/Preprocessors/CascadePreprocessor.swift
+2
-2
No files found.
Sources/MotionContext.swift
View file @
d21da35d
...
...
@@ -29,118 +29,172 @@
import
UIKit
public
class
MotionContext
{
/// A reference of motion identifiers to source views.
internal
var
motionIdentifierToSourceView
=
[
String
:
UIView
]()
/// A reference of motion identifiers to destination views.
internal
var
motionIdentifierToDestinationView
=
[
String
:
UIView
]()
internal
var
snapshotViews
=
[
UIView
:
UIView
]()
internal
var
viewAlphas
=
[
UIView
:
CGFloat
]()
internal
var
targetStates
=
[
UIView
:
MotionTargetState
]()
internal
var
superviewToNoSnapshotSubviewMap
:
[
UIView
:
[(
Int
,
UIView
)]]
=
[:]
internal
var
defaultCoordinateSpace
:
MotionCoordinateSpace
=
.
local
/// A reference of the snapshot to source/destination view.
internal
var
viewToSnapshot
=
[
UIView
:
UIView
]()
/// A reference to the view to view alpha value.
internal
var
viewToAlphas
=
[
UIView
:
CGFloat
]()
/// A reference of view to transition target state.
internal
var
viewToTargetState
=
[
UIView
:
MotionTargetState
]()
/// A reference of the superview to the subviews snapshots.
internal
var
superviewToNoSnapshotSubviewMap
=
[
UIView
:
[(
Int
,
UIView
)]]()
/// A reference to the default coordinate space for transitions.
internal
var
defaultCoordinateSpace
=
MotionCoordinateSpace
.
local
/// The container view holding all of the animating views.
public
let
container
:
UIView
/// A flattened list of all views from the source view controller.
public
var
fromViews
:
[
UIView
]
!
/// A flattened list of all views from the destination view controller.
public
var
toViews
:
[
UIView
]
!
/**
An initializer that accepts a container transition view.
- Parameter container: A UIView.
*/
internal
init
(
container
:
UIView
)
{
self
.
container
=
container
}
}
internal
func
set
(
fromViews
:
[
UIView
],
toViews
:
[
UIView
])
{
internal
extension
MotionContext
{
/**
Sets the from-views and to-views within the transition context.
- Parameter fromViews: An Array of UIViews.
- Parameter toViews: An Array of UIViews.
*/
func
set
(
fromViews
:
[
UIView
],
toViews
:
[
UIView
])
{
self
.
fromViews
=
fromViews
self
.
toViews
=
toViews
process
(
views
:
fromViews
,
id
Map
:
&
motionIdentifierToSourceView
)
process
(
views
:
toViews
,
id
Map
:
&
motionIdentifierToDestinationView
)
map
(
views
:
fromViews
,
identifier
Map
:
&
motionIdentifierToSourceView
)
map
(
views
:
toViews
,
identifier
Map
:
&
motionIdentifierToDestinationView
)
}
internal
func
process
(
views
:
[
UIView
],
idMap
:
inout
[
String
:
UIView
])
{
for
view
in
views
{
view
.
layer
.
removeAllAnimations
()
if
container
.
convert
(
view
.
bounds
,
from
:
view
)
.
intersects
(
container
.
bounds
)
{
if
let
motionIdentifier
=
view
.
motionIdentifier
{
idMap
[
motionIdentifier
]
=
view
/**
Maps the views to their respective identifier index.
- Parameter views: An Array of UIViews.
- Parameter identifierMap: A Dicionary of String to UIView pairs.
*/
func
map
(
views
:
[
UIView
],
identifierMap
:
inout
[
String
:
UIView
])
{
for
v
in
views
{
v
.
layer
.
removeAllAnimations
()
if
container
.
convert
(
v
.
bounds
,
from
:
v
)
.
intersects
(
container
.
bounds
)
{
if
let
i
=
v
.
motionIdentifier
{
identifierMap
[
i
]
=
v
}
if
let
transitions
=
view
.
motionTransitions
{
targetStates
[
view
]
=
MotionTargetState
(
transitions
:
transitions
)
if
let
i
=
v
.
motionTransitions
{
viewToTargetState
[
v
]
=
MotionTargetState
(
transitions
:
i
)
}
}
}
}
}
public
extension
MotionContext
{
/**
The container holding all of the animating views
*/
public
let
container
:
UIView
/**
A flattened list of all views from source ViewController
*/
public
var
fromViews
:
[
UIView
]
!
/**
A flattened list of all views from destination ViewController
A subscript that takes a given view and retrieves a
MotionTargetState if one exists.
- Parameter view: A UIView.
- Returns: An optional MotionTargetState.
*/
public
var
toViews
:
[
UIView
]
!
subscript
(
view
:
UIView
)
->
MotionTargetState
?
{
get
{
return
viewToTargetState
[
view
]
}
set
{
viewToTargetState
[
view
]
=
newValue
}
}
}
// public
extension
MotionContext
{
public
extension
MotionContext
{
/**
- Returns: a source view matching the motionIdentifier, nil if not found
Retrieves a source view matching the motionIdentifier, nil if not found.
- Parameter for motionIdentifier: A String.
- Returns: An optional UIView.
*/
public
func
sourceView
(
for
motionIdentifier
:
String
)
->
UIView
?
{
func
sourceView
(
for
motionIdentifier
:
String
)
->
UIView
?
{
return
motionIdentifierToSourceView
[
motionIdentifier
]
}
/**
- Returns: a destination view matching the motionIdentifier, nil if not found
Retrieves a destination view matching the motionIdentifier, nil if not found.
- Parameter for motionIdentifier: A String.
- Returns: An optional UIView.
*/
public
func
destinationView
(
for
motionIdentifier
:
String
)
->
UIView
?
{
func
destinationView
(
for
motionIdentifier
:
String
)
->
UIView
?
{
return
motionIdentifierToDestinationView
[
motionIdentifier
]
}
/**
- Returns: a view with the same motionIdentifier, but on different view controller, nil if not found
Retrieves the matching view with the same motionIdentifier found in the
source and destination view controllers.
- Returns: An optional UIView.
*/
public
func
pairedView
(
for
view
:
UIView
)
->
UIView
?
{
if
let
id
=
view
.
motionIdentifier
{
if
sourceView
(
for
:
id
)
==
view
{
return
destinationView
(
for
:
id
)
}
else
if
destinationView
(
for
:
id
)
==
view
{
return
sourceView
(
for
:
id
)
func
transitionPairedView
(
for
view
:
UIView
)
->
UIView
?
{
if
let
i
=
view
.
motionIdentifier
{
if
view
==
sourceView
(
for
:
i
)
{
return
destinationView
(
for
:
i
)
}
else
if
view
==
destinationView
(
for
:
i
)
{
return
sourceView
(
for
:
i
)
}
}
return
nil
}
/**
- Returns: a snapshot view for animation
Retrieves the snapshot view for a given view.
- Parameter for view: A UIView.
- Returns: A UIView.
*/
public
func
snapshotView
(
for
view
:
UIView
)
->
UIView
{
if
let
snapshot
=
snapshotViews
[
view
]
{
return
snapshot
func
snapshotView
(
for
view
:
UIView
)
->
UIView
{
if
let
v
=
viewToSnapshot
[
view
]
{
return
v
}
var
containerView
=
container
let
coordinateSpace
=
targetStates
[
view
]?
.
coordinateSpace
??
defaultCoordinateSpace
let
coordinateSpace
=
viewToTargetState
[
view
]?
.
coordinateSpace
??
defaultCoordinateSpace
switch
coordinateSpace
{
case
.
local
:
containerView
=
view
while
containerView
!=
container
,
snapshotViews
[
containerView
]
==
nil
,
let
superview
=
containerView
.
superview
{
while
containerView
!=
container
,
nil
==
viewToSnapshot
[
containerView
],
let
superview
=
containerView
.
superview
{
containerView
=
superview
}
if
let
snapshot
=
snapshotViews
[
containerView
]
{
if
let
snapshot
=
viewToSnapshot
[
containerView
]
{
containerView
=
snapshot
}
case
.
sameParent
:
containerView
=
view
.
superview
!
case
.
global
:
break
}
unhide
(
view
:
view
)
// capture a snapshot without alpha & cornerRadius
// Capture a snapshot without the alpha & cornerRadius values.
let
oldCornerRadius
=
view
.
layer
.
cornerRadius
let
oldAlpha
=
view
.
alpha
view
.
layer
.
cornerRadius
=
0
let
oldAlpha
=
view
.
alpha
view
.
alpha
=
1
let
snapshot
:
UIView
...
...
@@ -149,47 +203,56 @@ extension MotionContext {
switch
snapshotType
{
case
.
normal
:
snapshot
=
view
.
snapshotView
(
afterScreenUpdates
:
true
)
!
case
.
layerRender
:
snapshot
=
view
.
slowSnapshotView
()
case
.
noSnapshot
:
if
superviewToNoSnapshotSubviewMap
[
view
.
superview
!
]
==
nil
{
if
nil
==
superviewToNoSnapshotSubviewMap
[
view
.
superview
!
]
{
superviewToNoSnapshotSubviewMap
[
view
.
superview
!
]
=
[]
}
superviewToNoSnapshotSubviewMap
[
view
.
superview
!
]
!.
append
((
view
.
superview
!.
subviews
.
index
(
of
:
view
)
!
,
view
))
snapshot
=
view
case
.
optimized
:
#if os(tvOS)
snapshot
=
view
.
snapshotView
(
afterScreenUpdates
:
true
)
!
#else
if
#available(iOS 9.0, *)
,
let
stackView
=
view
as?
UIStackView
{
snapshot
=
stackView
.
slowSnapshotView
()
}
else
if
let
imageView
=
view
as?
UIImageView
,
view
.
subviews
.
isEmpty
{
let
contentView
=
UIImageView
(
image
:
imageView
.
image
)
contentView
.
frame
=
imageView
.
bounds
contentView
.
contentMode
=
imageView
.
contentMode
contentView
.
tintColor
=
imageView
.
tintColor
contentView
.
backgroundColor
=
imageView
.
backgroundColor
let
snapShotView
=
UIView
()
snapShotView
.
addSubview
(
contentView
)
snapshot
=
snapShotView
}
else
if
let
barView
=
view
as?
UINavigationBar
,
barView
.
isTranslucent
{
let
newBarView
=
UINavigationBar
(
frame
:
barView
.
frame
)
newBarView
.
barStyle
=
barView
.
barStyle
newBarView
.
tintColor
=
barView
.
tintColor
newBarView
.
barTintColor
=
barView
.
barTintColor
newBarView
.
clipsToBounds
=
false
}
else
if
let
navigationBar
=
view
as?
UINavigationBar
,
navigationBar
.
isTranslucent
{
let
newNavigationBar
=
UINavigationBar
(
frame
:
navigationBar
.
frame
)
newNavigationBar
.
barStyle
=
navigationBar
.
barStyle
newNavigationBar
.
tintColor
=
navigationBar
.
tintColor
newNavigationBar
.
barTintColor
=
navigationBar
.
barTintColor
newNavigationBar
.
clipsToBounds
=
false
// Take a snapshot without the background.
navigationBar
.
layer
.
sublayers
!
[
0
]
.
opacity
=
0
let
realSnapshot
=
navigationBar
.
snapshotView
(
afterScreenUpdates
:
true
)
!
navigationBar
.
layer
.
sublayers
!
[
0
]
.
opacity
=
1
// take a snapshot without the background
barView
.
layer
.
sublayers
!
[
0
]
.
opacity
=
0
let
realSnapshot
=
barView
.
snapshotView
(
afterScreenUpdates
:
true
)
!
barView
.
layer
.
sublayers
!
[
0
]
.
opacity
=
1
newNavigationBar
.
addSubview
(
realSnapshot
)
snapshot
=
newNavigationBar
newBarView
.
addSubview
(
realSnapshot
)
snapshot
=
newBarView
}
else
if
let
effectView
=
view
as?
UIVisualEffectView
{
snapshot
=
UIVisualEffectView
(
effect
:
effectView
.
effect
)
snapshot
.
frame
=
effectView
.
bounds
}
else
{
snapshot
=
view
.
snapshotView
(
afterScreenUpdates
:
true
)
!
}
...
...
@@ -205,12 +268,14 @@ extension MotionContext {
view
.
layer
.
cornerRadius
=
oldCornerRadius
view
.
alpha
=
oldAlpha
if
snapshotType
!=
.
noSnapshot
{
if
.
noSnapshot
!=
snapshotType
{
snapshot
.
layer
.
allowsGroupOpacity
=
false
if
!
(
view
is
UINavigationBar
),
let
contentView
=
snapshot
.
subviews
.
get
(
0
)
{
// the Snapshot's contentView must have hold the cornerRadius value,
// since the snapshot might not have maskToBounds set
/**
The snapshot's contentView must have the cornerRadius value,
since the snapshot might not have maskToBounds set
*/
contentView
.
layer
.
cornerRadius
=
view
.
layer
.
cornerRadius
contentView
.
layer
.
masksToBounds
=
true
}
...
...
@@ -241,44 +306,48 @@ extension MotionContext {
hide
(
view
:
view
)
if
let
pairedView
=
pairedView
(
for
:
view
),
let
pairedSnapshot
=
snapshotViews
[
pairedView
]
{
if
let
pairedView
=
transitionPairedView
(
for
:
view
),
let
pairedSnapshot
=
viewToSnapshot
[
pairedView
]
{
let
siblingViews
=
pairedView
.
superview
!.
subviews
let
nextSiblings
=
siblingViews
[
siblingViews
.
index
(
of
:
pairedView
)
!+
1
..<
siblingViews
.
count
]
containerView
.
addSubview
(
pairedSnapshot
)
containerView
.
addSubview
(
snapshot
)
for
subview
in
pairedView
.
subviews
{
insertGlobalViewTree
(
view
:
subview
)
}
for
sibling
in
nextSiblings
{
insertGlobalViewTree
(
view
:
sibling
)
}
}
else
{
containerView
.
addSubview
(
snapshot
)
}
containerView
.
addSubview
(
snapshot
)
snapshotViews
[
view
]
=
snapshot
viewToSnapshot
[
view
]
=
snapshot
return
snapshot
}
/**
Inserts the given view into the global context space.
- Parameter view: A UIView.
*/
func
insertGlobalViewTree
(
view
:
UIView
)
{
if
targetStates
[
view
]?
.
coordinateSpace
==
.
global
,
let
snapshot
=
snapshotViews
[
view
]
{
if
.
global
==
viewToTargetState
[
view
]?
.
coordinateSpace
,
let
snapshot
=
viewToSnapshot
[
view
]
{
container
.
addSubview
(
snapshot
)
}
for
subview
in
view
.
subviews
{
insertGlobalViewTree
(
view
:
subview
)
}
}
public
subscript
(
view
:
UIView
)
->
MotionTargetState
?
{
get
{
return
targetStates
[
view
]
}
set
{
targetStates
[
view
]
=
newValue
for
v
in
view
.
subviews
{
insertGlobalViewTree
(
view
:
v
)
}
}
public
func
clean
()
{
/// Restores the transition subview map with its superview.
func
clean
()
{
for
(
superview
,
subviews
)
in
superviewToNoSnapshotSubviewMap
{
for
(
index
,
view
)
in
subviews
.
reversed
()
{
superview
.
insertSubview
(
view
,
at
:
index
)
...
...
@@ -287,81 +356,133 @@ extension MotionContext {
}
}
// internal
extension
MotionContext
{
public
func
hide
(
view
:
UIView
)
{
if
viewAlphas
[
view
]
==
nil
,
self
[
view
]?
.
snapshotType
!=
.
noSnapshot
{
internal
extension
MotionContext
{
/**
Hides a given view.
- Parameter view: A UIView.
*/
func
hide
(
view
:
UIView
)
{
guard
nil
==
viewToAlphas
[
view
],
.
noSnapshot
!=
self
[
view
]?
.
snapshotType
else
{
return
}
if
view
is
UIVisualEffectView
{
view
.
isHidden
=
true
viewAlphas
[
view
]
=
1
viewToAlphas
[
view
]
=
1
}
else
{
view
Alphas
[
view
]
=
view
.
isOpaque
?
.
infinity
:
view
.
alpha
viewTo
Alphas
[
view
]
=
view
.
isOpaque
?
.
infinity
:
view
.
alpha
view
.
alpha
=
0
}
}
/**
Shows a given view that was hidden.
- Parameter view: A UIView.
*/
func
unhide
(
view
:
UIView
)
{
guard
let
oldAlpha
=
viewToAlphas
[
view
]
else
{
return
}
public
func
unhide
(
view
:
UIView
)
{
if
let
oldAlpha
=
viewAlphas
[
view
]
{
if
view
is
UIVisualEffectView
{
view
.
isHidden
=
false
}
else
if
oldAlpha
==
.
infinity
{
view
.
alpha
=
1
view
.
isOpaque
=
true
}
else
{
view
.
alpha
=
oldAlpha
}
viewAlphas
[
view
]
=
nil
}
viewToAlphas
[
view
]
=
nil
}
internal
func
unhideAll
()
{
for
view
in
viewAlphas
.
keys
{
unhide
(
view
:
view
)
/// Shows all given views that are hidden.
func
unhideAll
()
{
for
v
in
viewToAlphas
.
keys
{
unhide
(
view
:
v
)
}
viewAlphas
.
removeAll
()
viewToAlphas
.
removeAll
()
}
internal
func
unhide
(
rootView
:
UIView
)
{
/**
Show a given view and its subviews that are hidden.
- Parameter rootView: A UIView.
*/
func
unhide
(
rootView
:
UIView
)
{
unhide
(
view
:
rootView
)
for
subview
in
rootView
.
subviews
{
unhide
(
rootView
:
subview
)
}
}
internal
func
removeAllSnapshots
()
{
f
or
(
view
,
snapshot
)
in
snapshotViews
{
if
view
!=
s
napshot
{
// do not remove when it is using .useNoSnapshot
snapshot
.
removeFromSuperview
()
/// Removes all snapshots that are not using .useNoSnapshot.
f
unc
removeAllSnapshots
()
{
for
(
k
,
v
)
in
viewToS
napshot
{
if
k
!=
v
{
v
.
removeFromSuperview
()
}
}
}
internal
func
removeSnapshots
(
rootView
:
UIView
)
{
if
let
snapshot
=
snapshotViews
[
rootView
],
snapshot
!=
rootView
{
snapshot
.
removeFromSuperview
()
/**
Removes the snapshots for a given view and all its subviews.
- Parameter rootView: A UIVIew.
*/
func
removeSnapshots
(
rootView
:
UIView
)
{
if
let
v
=
viewToSnapshot
[
rootView
],
v
!=
rootView
{
v
.
removeFromSuperview
()
}
for
subview
in
rootView
.
subviews
{
removeSnapshots
(
rootView
:
subview
)
for
v
in
rootView
.
subviews
{
removeSnapshots
(
rootView
:
v
)
}
}
internal
func
snapshots
(
rootView
:
UIView
)
->
[
UIView
]
{
/**
Retrieves the snapshots for a given view and all its subviews.
- Parameter rootView: A UIView.
- Returns: An Array of UIViews.
*/
func
snapshots
(
rootView
:
UIView
)
->
[
UIView
]
{
var
snapshots
=
[
UIView
]()
for
v
in
rootView
.
flattenedViewHierarchy
{
if
let
snapshot
=
snapshotViews
[
v
]
{
if
let
snapshot
=
viewToSnapshot
[
v
]
{
snapshots
.
append
(
snapshot
)
}
}
return
snapshots
}
internal
func
loadViewAlpha
(
rootView
:
UIView
)
{
/**
Sets the alpha values for a given view and its subviews to the
stored alpha value.
- Parameter rootView: A UIView.
*/
func
loadViewAlpha
(
rootView
:
UIView
)
{
if
let
storedAlpha
=
rootView
.
motionAlpha
{
rootView
.
alpha
=
storedAlpha
rootView
.
motionAlpha
=
nil
}
for
subview
in
rootView
.
subviews
{
loadViewAlpha
(
rootView
:
subview
)
}
}
internal
func
storeViewAlpha
(
rootView
:
UIView
)
{
rootView
.
motionAlpha
=
viewAlphas
[
rootView
]
/**
Stores the alpha values for a given view and its subviews.
- Parameter rootView: A UIView.
*/
func
storeViewAlpha
(
rootView
:
UIView
)
{
rootView
.
motionAlpha
=
viewToAlphas
[
rootView
]
for
subview
in
rootView
.
subviews
{
storeViewAlpha
(
rootView
:
subview
)
}
...
...
Sources/MotionController.swift
View file @
d21da35d
...
...
@@ -297,7 +297,7 @@ public extension MotionController {
}
let
s
=
MotionTargetState
(
transitions
:
transitions
)
let
v
=
context
.
p
airedView
(
for
:
view
)
??
view
let
v
=
context
.
transitionP
airedView
(
for
:
view
)
??
view
for
a
in
animators
{
a
.
apply
(
state
:
s
,
to
:
v
)
...
...
Sources/Preprocessors/CascadePreprocessor.swift
View file @
d21da35d
...
...
@@ -94,9 +94,9 @@ class CascadePreprocessor: BasePreprocessor {
let
delay
=
TimeInterval
(
i
)
*
deltaTime
+
initialDelay
func
applyDelay
(
view
:
UIView
)
{
if
context
.
p
airedView
(
for
:
view
)
==
nil
{
if
context
.
transitionP
airedView
(
for
:
view
)
==
nil
{
context
[
view
]?
.
delay
=
delay
}
else
if
delayMatchedViews
,
let
paired
=
context
.
p
airedView
(
for
:
view
)
{
}
else
if
delayMatchedViews
,
let
paired
=
context
.
transitionP
airedView
(
for
:
view
)
{
context
[
view
]?
.
delay
=
finalDelay
context
[
paired
]?
.
delay
=
finalDelay
}
...
...
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