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
2caa4eb1
Unverified
Commit
2caa4eb1
authored
Jun 05, 2017
by
Daniel Dahan
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
initial clean up for MotionCoreAnimationViewContext completed
parent
97383774
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
162 additions
and
135 deletions
+162
-135
Sources/Animator/MotionCoreAnimationViewContext.swift
+162
-135
No files found.
Sources/Animator/MotionCoreAnimationViewContext.swift
View file @
2caa4eb1
...
...
@@ -43,13 +43,11 @@ internal class MotionCoreAnimationViewContext: MotionAnimatorViewContext {
/// Layer which holds the overlay.
fileprivate
var
overlayLayer
:
CALayer
?
/**
Determines whether a view can be animated.
- Parameter view: A UIView.
- Parameter state: A MotionTargetState.
- Parameter isAppearing: A boolean indicating whether or not the
view is going to appear.
*/
override
func
clean
()
{
super
.
clean
()
overlayLayer
=
nil
}
override
class
func
canAnimate
(
view
:
UIView
,
state
:
MotionTargetState
,
isAppearing
:
Bool
)
->
Bool
{
return
nil
!=
state
.
position
||
nil
!=
state
.
size
||
...
...
@@ -69,11 +67,73 @@ internal class MotionCoreAnimationViewContext: MotionAnimatorViewContext {
state
.
forceAnimate
}
override
func
apply
(
state
:
MotionTargetState
)
{
let
ts
=
viewState
(
targetState
:
state
)
for
(
key
,
targetValue
)
in
ts
{
if
nil
==
transitionStates
[
key
]
{
let
current
=
currentValue
(
for
:
key
)
transitionStates
[
key
]
=
(
current
,
current
)
}
animate
(
key
:
key
,
beginTime
:
0
,
fromValue
:
targetValue
,
toValue
:
targetValue
)
}
}
override
func
resume
(
elapsedTime
:
TimeInterval
,
isReversed
:
Bool
)
{
for
(
key
,
(
fromValue
,
toValue
))
in
transitionStates
{
transitionStates
[
key
]
=
(
currentValue
(
for
:
key
),
!
isReversed
?
toValue
:
fromValue
)
}
targetState
.
duration
=
isReversed
?
elapsedTime
-
targetState
.
delay
:
duration
-
elapsedTime
animate
(
delay
:
max
(
0
,
targetState
.
delay
-
elapsedTime
))
}
override
func
seek
(
to
elapsedTime
:
TimeInterval
)
{
seek
(
layer
:
snapshot
.
layer
,
elapsedTime
:
elapsedTime
)
if
let
v
=
contentLayer
{
seek
(
layer
:
v
,
elapsedTime
:
elapsedTime
)
}
if
let
v
=
overlayLayer
{
seek
(
layer
:
v
,
elapsedTime
:
elapsedTime
)
}
}
override
func
startAnimations
(
isAppearing
:
Bool
)
{
if
let
beginState
=
targetState
.
beginState
?
.
state
{
let
appeared
=
viewState
(
targetState
:
beginState
)
for
(
k
,
v
)
in
appeared
{
snapshot
.
layer
.
setValue
(
v
,
forKeyPath
:
k
)
}
if
let
(
k
,
v
)
=
beginState
.
overlay
{
let
overlay
=
getOverlayLayer
()
overlay
.
backgroundColor
=
k
overlay
.
opacity
=
Float
(
v
)
}
}
let
disappeared
=
viewState
(
targetState
:
targetState
)
for
(
k
,
v
)
in
disappeared
{
let
isAppearingState
=
currentValue
(
for
:
k
)
let
toValue
=
isAppearing
?
isAppearingState
:
v
let
fromValue
=
!
isAppearing
?
isAppearingState
:
v
transitionStates
[
k
]
=
(
fromValue
,
toValue
)
}
animate
(
delay
:
targetState
.
delay
)
}
}
extension
MotionCoreAnimationViewContext
{
/**
Lazy loads the overlay layer.
- Returns: A CALayer.
*/
func
getOverlayLayer
()
->
CALayer
{
f
ileprivate
f
unc
getOverlayLayer
()
->
CALayer
{
if
nil
==
overlayLayer
{
overlayLayer
=
CALayer
()
overlayLayer
!.
frame
=
snapshot
.
bounds
...
...
@@ -89,7 +149,7 @@ internal class MotionCoreAnimationViewContext: MotionAnimatorViewContext {
- Parameter for key: A String.
- Returns: An optional String.
*/
func
overlayKey
(
for
key
:
String
)
->
String
?
{
f
ileprivate
f
unc
overlayKey
(
for
key
:
String
)
->
String
?
{
guard
key
.
hasPrefix
(
"overlay."
)
else
{
return
nil
}
...
...
@@ -104,7 +164,7 @@ internal class MotionCoreAnimationViewContext: MotionAnimatorViewContext {
- Parameter for key: A String.
- Returns: An optional Any value.
*/
func
currentValue
(
for
key
:
String
)
->
Any
?
{
f
ileprivate
f
unc
currentValue
(
for
key
:
String
)
->
Any
?
{
if
let
key
=
overlayKey
(
for
:
key
)
{
return
overlayLayer
?
.
value
(
forKeyPath
:
key
)
}
...
...
@@ -124,7 +184,7 @@ internal class MotionCoreAnimationViewContext: MotionAnimatorViewContext {
- Parameter toValue: An optional Any value.
- Parameter ignoreArc: A Boolean value to ignore an arc position.
*/
func
getAnimation
(
key
:
String
,
beginTime
:
TimeInterval
,
fromValue
:
Any
?,
toValue
:
Any
?,
ignoreArc
:
Bool
=
false
)
->
CAPropertyAnimation
{
f
ileprivate
f
unc
getAnimation
(
key
:
String
,
beginTime
:
TimeInterval
,
fromValue
:
Any
?,
toValue
:
Any
?,
ignoreArc
:
Bool
=
false
)
->
CAPropertyAnimation
{
let
key
=
overlayKey
(
for
:
key
)
??
key
let
anim
:
CAPropertyAnimation
...
...
@@ -182,39 +242,49 @@ internal class MotionCoreAnimationViewContext: MotionAnimatorViewContext {
- Parameter toValue: A optional Any value.
- Returns: A TimeInterval.
*/
func
animate
(
key
:
String
,
beginTime
:
TimeInterval
,
fromValue
:
Any
?,
toValue
:
Any
?)
->
TimeInterval
{
@discardableResult
fileprivate
func
animate
(
key
:
String
,
beginTime
:
TimeInterval
,
fromValue
:
Any
?,
toValue
:
Any
?)
->
TimeInterval
{
let
anim
=
getAnimation
(
key
:
key
,
beginTime
:
beginTime
,
fromValue
:
fromValue
,
toValue
:
toValue
)
if
let
overlayKey
=
overlayKey
(
for
:
key
)
{
getOverlayLayer
()
.
add
(
anim
,
forKey
:
overlayKey
)
}
else
{
snapshot
.
layer
.
add
(
anim
,
forKey
:
key
)
switch
key
{
case
"cornerRadius"
,
"contentsRect"
,
"contentsScale"
:
contentLayer
?
.
add
(
anim
,
forKey
:
key
)
overlayLayer
?
.
add
(
anim
,
forKey
:
key
)
case
"bounds.size"
:
let
fromSize
=
(
fromValue
as?
NSValue
)
!.
cgSizeValue
let
toSize
=
(
toValue
as?
NSValue
)
!.
cgSizeValue
guard
let
fs
=
(
fromValue
as?
NSValue
)?
.
cgSizeValue
else
{
return
0
}
guard
let
ts
=
(
toValue
as?
NSValue
)?
.
cgSizeValue
else
{
return
0
}
// for the snapshotView(UIReplicantView): there is a
// subview(UIReplicantContentView) that is hosting the real snapshot image.
// because we are using CAAnimations and not UIView animations,
// The snapshotView will not layout during animations.
// we have to add two more animations to manually layout the content view.
let
f
romPosn
=
NSValue
(
cgPoint
:
fromSize
.
center
)
let
t
oPosn
=
NSValue
(
cgPoint
:
toSize
.
center
)
let
f
pn
=
NSValue
(
cgPoint
:
fs
.
center
)
let
t
pn
=
NSValue
(
cgPoint
:
ts
.
center
)
let
positionAnim
=
getAnimation
(
key
:
"position"
,
beginTime
:
0
,
fromValue
:
fromPosn
,
toValue
:
toPos
n
,
ignoreArc
:
true
)
positionAnim
.
beginTime
=
anim
.
beginTime
positionAnim
.
timingFunction
=
anim
.
timingFunction
positionAnim
.
duration
=
anim
.
duration
let
a
=
getAnimation
(
key
:
"position"
,
beginTime
:
0
,
fromValue
:
fpn
,
toValue
:
tp
n
,
ignoreArc
:
true
)
a
.
beginTime
=
anim
.
beginTime
a
.
timingFunction
=
anim
.
timingFunction
a
.
duration
=
anim
.
duration
contentLayer
?
.
add
(
positionAnim
,
forKey
:
"position"
)
contentLayer
?
.
add
(
a
,
forKey
:
"position"
)
contentLayer
?
.
add
(
anim
,
forKey
:
key
)
overlayLayer
?
.
add
(
positionAnim
,
forKey
:
"position"
)
overlayLayer
?
.
add
(
a
,
forKey
:
"position"
)
overlayLayer
?
.
add
(
anim
,
forKey
:
key
)
default
:
break
}
}
...
...
@@ -222,15 +292,23 @@ internal class MotionCoreAnimationViewContext: MotionAnimatorViewContext {
return
anim
.
duration
+
anim
.
beginTime
-
beginTime
}
func
animate
(
delay
:
TimeInterval
)
{
if
let
tf
=
targetState
.
timingFunction
{
timingFunction
=
tf
/**
Animates the contentLayer and overlayLayer with a given delay.
- Parameter delay: A TimeInterval.
*/
fileprivate
func
animate
(
delay
:
TimeInterval
)
{
if
let
v
=
targetState
.
timingFunction
{
timingFunction
=
v
}
duration
=
targetState
.
duration
!
if
let
v
=
targetState
.
duration
{
duration
=
v
}
let
beginTime
=
currentTime
+
delay
var
finalDuration
:
TimeInterval
=
duration
for
(
key
,
(
fromValue
,
toValue
))
in
transitionStates
{
let
neededTime
=
animate
(
key
:
key
,
beginTime
:
beginTime
,
fromValue
:
fromValue
,
toValue
:
toValue
)
finalDuration
=
max
(
finalDuration
,
neededTime
+
delay
)
...
...
@@ -240,110 +318,99 @@ internal class MotionCoreAnimationViewContext: MotionAnimatorViewContext {
}
/**
- Returns: a CALayer [keyPath:value] map for animation
Constructs a map of key paths to animation values.
- Parameter targetState state: A MotionTargetState.
- Returns: A map of key paths to animation values.
*/
func
viewState
(
targetState
:
MotionTargetState
)
->
[
String
:
Any
?]
{
var
targetState
=
targetState
var
rtn
=
[
String
:
Any
?]()
fileprivate
func
viewState
(
targetState
ts
:
MotionTargetState
)
->
[
String
:
Any
?]
{
var
ts
=
ts
var
values
=
[
String
:
Any
?]()
if
let
size
=
targetState
.
size
{
if
targetState
.
useScaleBasedSizeChange
??
self
.
targetState
.
useScaleBasedSizeChange
??
false
{
if
let
size
=
ts
.
size
{
if
ts
.
useScaleBasedSizeChange
??
targetState
.
useScaleBasedSizeChange
??
false
{
let
currentSize
=
snapshot
.
bounds
.
size
targetState
.
append
(
.
scale
(
x
:
size
.
width
/
currentSize
.
width
,
y
:
size
.
height
/
currentSize
.
height
))
ts
.
append
(
.
scale
(
x
:
size
.
width
/
currentSize
.
width
,
y
:
size
.
height
/
currentSize
.
height
))
}
else
{
rtn
[
"bounds.size"
]
=
NSValue
(
cgSize
:
size
)
values
[
"bounds.size"
]
=
NSValue
(
cgSize
:
size
)
}
}
if
let
position
=
targetState
.
position
{
rtn
[
"position"
]
=
NSValue
(
cgPoint
:
position
)
}
if
let
opacity
=
targetState
.
opacity
,
!
(
snapshot
is
UIVisualEffectView
)
{
rtn
[
"opacity"
]
=
NSNumber
(
value
:
opacity
)
}
if
let
cornerRadius
=
targetState
.
cornerRadius
{
rtn
[
"cornerRadius"
]
=
NSNumber
(
value
:
cornerRadius
.
native
)
}
if
let
backgroundColor
=
targetState
.
backgroundColor
{
rtn
[
"backgroundColor"
]
=
backgroundColor
}
if
let
zPosition
=
targetState
.
zPosition
{
rtn
[
"zPosition"
]
=
NSNumber
(
value
:
zPosition
.
native
)
}
if
let
borderWidth
=
targetState
.
borderWidth
{
rtn
[
"borderWidth"
]
=
NSNumber
(
value
:
borderWidth
.
native
)
if
let
position
=
ts
.
position
{
values
[
"position"
]
=
NSValue
(
cgPoint
:
position
)
}
if
let
borderColor
=
targetState
.
borderColor
{
rtn
[
"borderColor"
]
=
borderColor
if
let
opacity
=
ts
.
opacity
,
!
(
snapshot
is
UIVisualEffectView
)
{
values
[
"opacity"
]
=
NSNumber
(
value
:
opacity
)
}
if
let
masksToBounds
=
targetState
.
masksToBounds
{
rtn
[
"masksToBounds"
]
=
masksToBounds
if
let
cornerRadius
=
ts
.
cornerRadius
{
values
[
"cornerRadius"
]
=
NSNumber
(
value
:
cornerRadius
.
native
)
}
if
targetState
.
displayShadow
{
if
let
shadowColor
=
targetState
.
shadowColor
{
rtn
[
"shadowColor"
]
=
shadowColor
if
let
backgroundColor
=
ts
.
backgroundColor
{
values
[
"backgroundColor"
]
=
backgroundColor
}
if
let
shadowRadius
=
targetState
.
shadowRadius
{
rtn
[
"shadowRadius"
]
=
NSNumber
(
value
:
shadowRadius
.
native
)
if
let
zPosition
=
ts
.
zPosition
{
values
[
"zPosition"
]
=
NSNumber
(
value
:
zPosition
.
native
)
}
if
let
shadowOpacity
=
targetState
.
shadowOpacity
{
rtn
[
"shadowOpacity"
]
=
NSNumber
(
value
:
shadowOpacity
)
if
let
borderWidth
=
ts
.
borderWidth
{
values
[
"borderWidth"
]
=
NSNumber
(
value
:
borderWidth
.
native
)
}
if
let
shadowPath
=
targetState
.
shadowPath
{
rtn
[
"shadowPath"
]
=
shadowPath
if
let
borderColor
=
ts
.
borderColor
{
values
[
"borderColor"
]
=
borderColor
}
if
let
shadowOffset
=
targetState
.
shadowOffset
{
rtn
[
"shadowOffset"
]
=
NSValue
(
cgSize
:
shadowOffset
)
if
let
masksToBounds
=
ts
.
masksToBounds
{
values
[
"masksToBounds"
]
=
masksToBounds
}
if
ts
.
displayShadow
{
if
let
shadowColor
=
ts
.
shadowColor
{
values
[
"shadowColor"
]
=
shadowColor
}
if
let
contentsRect
=
targetState
.
contentsRect
{
rtn
[
"contentsRect"
]
=
NSValue
(
cgRect
:
contentsRect
)
if
let
shadowRadius
=
ts
.
shadowRadius
{
values
[
"shadowRadius"
]
=
NSNumber
(
value
:
shadowRadius
.
native
)
}
if
let
contentsScale
=
targetState
.
contentsScale
{
rtn
[
"contentsScale"
]
=
NSNumber
(
value
:
contentsScale
.
native
)
if
let
shadowOpacity
=
ts
.
shadowOpacity
{
values
[
"shadowOpacity"
]
=
NSNumber
(
value
:
shadowOpacity
)
}
if
let
transform
=
targetState
.
transform
{
rtn
[
"transform"
]
=
NSValue
(
caTransform3D
:
transform
)
if
let
shadowPath
=
ts
.
shadowPath
{
values
[
"shadowPath"
]
=
shadowPath
}
if
let
(
color
,
opacity
)
=
targetState
.
overlay
{
rtn
[
"overlay.backgroundColor"
]
=
color
rtn
[
"overlay.opacity"
]
=
NSNumber
(
value
:
opacity
.
native
)
if
let
shadowOffset
=
ts
.
shadowOffset
{
values
[
"shadowOffset"
]
=
NSValue
(
cgSize
:
shadowOffset
)
}
return
rtn
}
override
func
apply
(
state
:
MotionTargetState
)
{
let
targetState
=
viewState
(
targetState
:
state
)
for
(
key
,
targetValue
)
in
targetState
{
if
self
.
transitionStates
[
key
]
==
nil
{
let
current
=
currentValue
(
for
:
key
)
self
.
transitionStates
[
key
]
=
(
current
,
current
)
}
_
=
animate
(
key
:
key
,
beginTime
:
0
,
fromValue
:
targetValue
,
toValue
:
targetValue
)
if
let
contentsRect
=
ts
.
contentsRect
{
values
[
"contentsRect"
]
=
NSValue
(
cgRect
:
contentsRect
)
}
if
let
contentsScale
=
ts
.
contentsScale
{
values
[
"contentsScale"
]
=
NSNumber
(
value
:
contentsScale
.
native
)
}
override
func
resume
(
elapsedTime
:
TimeInterval
,
isReversed
:
Bool
)
{
for
(
key
,
(
fromValue
,
toValue
))
in
transitionStates
{
let
realToValue
=
!
isReversed
?
toValue
:
fromValue
let
realFromValue
=
currentValue
(
for
:
key
)
transitionStates
[
key
]
=
(
realFromValue
,
realToValue
)
if
let
transform
=
ts
.
transform
{
values
[
"transform"
]
=
NSValue
(
caTransform3D
:
transform
)
}
// we need to update the duration to reflect current state
targetState
.
duration
=
isReversed
?
elapsedTime
-
targetState
.
delay
:
duration
-
elapsedTime
if
let
(
color
,
opacity
)
=
ts
.
overlay
{
values
[
"overlay.backgroundColor"
]
=
color
values
[
"overlay.opacity"
]
=
NSNumber
(
value
:
opacity
.
native
)
}
let
realDelay
=
max
(
0
,
targetState
.
delay
-
elapsedTime
)
animate
(
delay
:
realDelay
)
return
values
}
func
seek
(
layer
:
CALayer
,
elapsedTime
:
TimeInterval
)
{
fileprivate
func
seek
(
layer
:
CALayer
,
elapsedTime
:
TimeInterval
)
{
let
timeOffset
=
elapsedTime
-
targetState
.
delay
for
(
key
,
anim
)
in
layer
.
animations
{
anim
.
speed
=
0
...
...
@@ -352,44 +419,4 @@ internal class MotionCoreAnimationViewContext: MotionAnimatorViewContext {
layer
.
add
(
anim
,
forKey
:
key
)
}
}
override
func
seek
(
to
elapsedTime
:
TimeInterval
)
{
seek
(
layer
:
snapshot
.
layer
,
elapsedTime
:
elapsedTime
)
if
let
contentLayer
=
contentLayer
{
seek
(
layer
:
contentLayer
,
elapsedTime
:
elapsedTime
)
}
if
let
overlayLayer
=
overlayLayer
{
seek
(
layer
:
overlayLayer
,
elapsedTime
:
elapsedTime
)
}
}
override
func
clean
()
{
super
.
clean
()
overlayLayer
=
nil
}
override
func
startAnimations
(
isAppearing
:
Bool
)
{
if
let
beginState
=
targetState
.
beginState
?
.
state
{
let
appeared
=
viewState
(
targetState
:
beginState
)
for
(
key
,
value
)
in
appeared
{
snapshot
.
layer
.
setValue
(
value
,
forKeyPath
:
key
)
}
if
let
(
color
,
opacity
)
=
beginState
.
overlay
{
let
overlay
=
getOverlayLayer
()
overlay
.
backgroundColor
=
color
overlay
.
opacity
=
Float
(
opacity
)
}
}
let
disappeared
=
viewState
(
targetState
:
targetState
)
for
(
key
,
disappearedState
)
in
disappeared
{
let
isAppearingState
=
currentValue
(
for
:
key
)
let
toValue
=
isAppearing
?
isAppearingState
:
disappearedState
let
fromValue
=
!
isAppearing
?
isAppearingState
:
disappearedState
transitionStates
[
key
]
=
(
fromValue
,
toValue
)
}
animate
(
delay
:
targetState
.
delay
)
}
}
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