Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
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
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
7f95d9b5
Commit
7f95d9b5
authored
Jan 19, 2016
by
Adam Barth
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #1303 from abarth/tween2
Introduce Tween and the new animation API
parents
548dbf08
bc20871c
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
462 additions
and
25 deletions
+462
-25
progress_indicator.dart
examples/widgets/progress_indicator.dart
+22
-24
animation.dart
packages/flutter/lib/animation.dart
+1
-0
tween.dart
packages/flutter/lib/src/animation/tween.dart
+376
-0
transitions.dart
packages/flutter/lib/src/widgets/transitions.dart
+63
-1
No files found.
examples/widgets/progress_indicator.dart
View file @
7f95d9b5
...
...
@@ -12,39 +12,38 @@ class ProgressIndicatorApp extends StatefulComponent {
class
_ProgressIndicatorAppState
extends
State
<
ProgressIndicatorApp
>
{
void
initState
()
{
super
.
initState
();
valueAnimation
=
new
ValuePerformance
<
double
>()
..
duration
=
const
Duration
(
milliseconds:
1500
)
..
variable
=
new
AnimatedValue
<
double
>(
0.0
,
end:
1.0
,
curve:
new
Interval
(
0.0
,
0.9
,
curve:
Curves
.
ease
)
,
reverseCurve:
Curves
.
ease
);
valueAnimation
.
addStatusListener
((
PerformanceStatus
status
)
{
controller
=
new
AnimationController
(
duration:
const
Duration
(
milliseconds:
1500
)
)..
play
(
AnimationDirection
.
forward
);
animation
=
new
ACurve
(
parent:
controller
,
curve:
new
Interval
(
0.0
,
0.9
,
curve:
Curves
.
ease
),
reverseCurve:
Curves
.
ease
).
.
addStatusListener
((
PerformanceStatus
status
)
{
if
(
status
==
PerformanceStatus
.
dismissed
||
status
==
PerformanceStatus
.
completed
)
reverseValueAnimationDirection
();
});
valueAnimation
.
play
(
valueAnimationDirection
);
}
ValuePerformance
<
double
>
valueA
nimation
;
Animation
Direction
valueAnimationDirection
=
AnimationDirection
.
forward
;
Animation
a
nimation
;
Animation
Controller
controller
;
void
handleTap
()
{
setState
(()
{
// valueAnimation.isAnimating is part of our build state
if
(
valueAnimation
.
isAnimating
)
valueAnimation
.
stop
();
if
(
controller
.
isAnimating
)
controller
.
stop
();
else
valueAnimation
.
resume
();
controller
.
resume
();
});
}
void
reverseValueAnimationDirection
()
{
valueAnimationDirection
=
(
valueAnimationD
irection
==
AnimationDirection
.
forward
)
AnimationDirection
direction
=
(
controller
.
d
irection
==
AnimationDirection
.
forward
)
?
AnimationDirection
.
reverse
:
AnimationDirection
.
forward
;
valueAnimation
.
play
(
valueAnimationD
irection
);
controller
.
play
(
d
irection
);
}
Widget
buildIndicators
(
BuildContext
context
)
{
...
...
@@ -55,19 +54,19 @@ class _ProgressIndicatorAppState extends State<ProgressIndicatorApp> {
),
new
LinearProgressIndicator
(),
new
LinearProgressIndicator
(),
new
LinearProgressIndicator
(
value:
valueAnimation
.
value
),
new
LinearProgressIndicator
(
value:
animation
.
progress
),
new
CircularProgressIndicator
(),
new
SizedBox
(
width:
20.0
,
height:
20.0
,
child:
new
CircularProgressIndicator
(
value:
valueAnimation
.
value
)
child:
new
CircularProgressIndicator
(
value:
animation
.
progress
)
),
new
SizedBox
(
width:
50.0
,
height:
30.0
,
child:
new
CircularProgressIndicator
(
value:
valueAnimation
.
value
)
child:
new
CircularProgressIndicator
(
value:
animation
.
progress
)
),
new
Text
(
"
${(
valueAnimation.value * 100.0).toStringAsFixed(1)}
%"
+
(
valueAnimation
.
isAnimating
?
''
:
' (paused)'
))
new
Text
(
"
${(
animation.progress * 100.0).toStringAsFixed(1)}
%"
+
(
controller
.
isAnimating
?
''
:
' (paused)'
))
];
return
new
Column
(
children:
indicators
...
...
@@ -82,9 +81,8 @@ class _ProgressIndicatorAppState extends State<ProgressIndicatorApp> {
onTap:
handleTap
,
child:
new
Container
(
padding:
const
EdgeDims
.
symmetric
(
vertical:
12.0
,
horizontal:
8.0
),
child:
new
BuilderTransition
(
variables:
<
AnimatedValue
<
double
>>[
valueAnimation
.
variable
],
performance:
valueAnimation
.
view
,
child:
new
AnimationWatchingBuilder
(
watchable:
animation
,
builder:
buildIndicators
)
)
...
...
packages/flutter/lib/animation.dart
View file @
7f95d9b5
...
...
@@ -16,3 +16,4 @@ export 'src/animation/performance.dart';
export
'src/animation/scroll_behavior.dart'
;
export
'src/animation/simulation_stepper.dart'
;
export
'src/animation/ticker.dart'
;
export
'src/animation/tween.dart'
;
packages/flutter/lib/src/animation/tween.dart
0 → 100644
View file @
7f95d9b5
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'dart:async'
;
import
'dart:ui'
show
Color
,
Size
,
Rect
,
VoidCallback
,
lerpDouble
;
import
'package:newton/newton.dart'
;
import
'animated_value.dart'
;
import
'curves.dart'
;
import
'forces.dart'
;
import
'listener_helpers.dart'
;
import
'simulation_stepper.dart'
;
abstract
class
Watchable
{
const
Watchable
();
/// Calls the listener every time the progress of the performance changes.
void
addListener
(
VoidCallback
listener
);
/// Stop calling the listener every time the progress of the performance changes.
void
removeListener
(
VoidCallback
listener
);
/// Calls listener every time the status of the performance changes.
void
addStatusListener
(
PerformanceStatusListener
listener
);
/// Stops calling the listener every time the status of the performance changes.
void
removeStatusListener
(
PerformanceStatusListener
listener
);
/// The current status of this animation.
PerformanceStatus
get
status
;
/// The current direction of the animation.
AnimationDirection
get
direction
;
/// The direction used to select the current curve.
///
/// The curve direction is only reset when we hit the beginning or the end of
/// the timeline to avoid discontinuities in the value of any variables this
/// performance is used to animate.
AnimationDirection
get
curveDirection
;
/// Whether this animation is stopped at the beginning.
bool
get
isDismissed
=>
status
==
PerformanceStatus
.
dismissed
;
/// Whether this animation is stopped at the end.
bool
get
isCompleted
=>
status
==
PerformanceStatus
.
completed
;
String
toString
()
{
return
'
$runtimeType
(
${toStringDetails()}
)'
;
}
String
toStringDetails
()
{
assert
(
status
!=
null
);
assert
(
direction
!=
null
);
String
icon
;
switch
(
status
)
{
case
PerformanceStatus
.
forward
:
icon
=
'
\
u25B6'
;
// >
break
;
case
PerformanceStatus
.
reverse
:
icon
=
'
\
u25C0'
;
// <
break
;
case
PerformanceStatus
.
completed
:
switch
(
direction
)
{
case
AnimationDirection
.
forward
:
icon
=
'
\
u23ED'
;
// >>|
break
;
case
AnimationDirection
.
reverse
:
icon
=
'
\
u29CF'
;
// <|
break
;
}
break
;
case
PerformanceStatus
.
dismissed
:
switch
(
direction
)
{
case
AnimationDirection
.
forward
:
icon
=
'
\
u29D0'
;
// |>
break
;
case
AnimationDirection
.
reverse
:
icon
=
'
\
u23EE'
;
// |<<
break
;
}
break
;
}
assert
(
icon
!=
null
);
return
'
$icon
'
;
}
}
abstract
class
ProxyWatchableMixin
implements
Watchable
{
Watchable
get
parent
;
void
addListener
(
VoidCallback
listener
)
=>
parent
.
addListener
(
listener
);
void
removeListener
(
VoidCallback
listener
)
=>
parent
.
removeListener
(
listener
);
void
addStatusListener
(
PerformanceStatusListener
listener
)
=>
parent
.
addStatusListener
(
listener
);
void
removeStatusListener
(
PerformanceStatusListener
listener
)
=>
parent
.
removeStatusListener
(
listener
);
PerformanceStatus
get
status
=>
parent
.
status
;
AnimationDirection
get
direction
=>
parent
.
direction
;
AnimationDirection
get
curveDirection
=>
parent
.
curveDirection
;
}
abstract
class
Evaluatable
<
T
>
{
const
Evaluatable
();
T
evaluate
(
double
t
);
WatchableValue
<
T
>
watch
(
Animation
parent
)
{
return
new
WatchableValue
<
T
>(
parent:
parent
,
evaluatable:
this
);
}
}
class
WatchableValue
<
T
>
extends
Watchable
with
ProxyWatchableMixin
{
WatchableValue
({
this
.
parent
,
this
.
evaluatable
});
final
Animation
parent
;
final
Evaluatable
<
T
>
evaluatable
;
T
get
value
=>
evaluatable
.
evaluate
(
parent
.
progress
);
}
abstract
class
Animation
extends
Watchable
{
/// The current progress of this animation (a value from 0.0 to 1.0).
double
get
progress
;
String
toStringDetails
()
{
return
'
${super.toStringDetails()}
${progress.toStringAsFixed(3)}
'
;
}
}
class
AnimationController
extends
Animation
with
EagerListenerMixin
,
LocalPerformanceListenersMixin
,
LocalPerformanceStatusListenersMixin
{
AnimationController
({
this
.
duration
,
double
progress
,
this
.
debugLabel
})
{
_timeline
=
new
SimulationStepper
(
_tick
);
if
(
progress
!=
null
)
_timeline
.
value
=
progress
.
clamp
(
0.0
,
1.0
);
}
/// A label that is used in the [toString] output. Intended to aid with
/// identifying performance instances in debug output.
final
String
debugLabel
;
/// Returns a [Animation] for this performance,
/// so that a pointer to this object can be passed around without
/// allowing users of that pointer to mutate the Performance state.
Animation
get
view
=>
this
;
/// The length of time this performance should last.
Duration
duration
;
SimulationStepper
_timeline
;
AnimationDirection
get
direction
=>
_direction
;
AnimationDirection
_direction
=
AnimationDirection
.
forward
;
AnimationDirection
get
curveDirection
=>
_curveDirection
;
AnimationDirection
_curveDirection
=
AnimationDirection
.
forward
;
/// The progress of this performance along the timeline.
///
/// Note: Setting this value stops the current animation.
double
get
progress
=>
_timeline
.
value
.
clamp
(
0.0
,
1.0
);
void
set
progress
(
double
t
)
{
stop
();
_timeline
.
value
=
t
.
clamp
(
0.0
,
1.0
);
_checkStatusChanged
();
}
/// Whether this animation is currently animating in either the forward or reverse direction.
bool
get
isAnimating
=>
_timeline
.
isAnimating
;
PerformanceStatus
get
status
{
if
(!
isAnimating
&&
progress
==
1.0
)
return
PerformanceStatus
.
completed
;
if
(!
isAnimating
&&
progress
==
0.0
)
return
PerformanceStatus
.
dismissed
;
return
_direction
==
AnimationDirection
.
forward
?
PerformanceStatus
.
forward
:
PerformanceStatus
.
reverse
;
}
/// Starts running this animation forwards (towards the end).
Future
forward
()
=>
play
(
AnimationDirection
.
forward
);
/// Starts running this animation in reverse (towards the beginning).
Future
reverse
()
=>
play
(
AnimationDirection
.
reverse
);
/// Starts running this animation in the given direction.
Future
play
(
AnimationDirection
direction
)
{
_direction
=
direction
;
return
resume
();
}
/// Resumes this animation in the most recent direction.
Future
resume
()
{
return
_animateTo
(
_direction
==
AnimationDirection
.
forward
?
1.0
:
0.0
);
}
/// Stops running this animation.
void
stop
()
{
_timeline
.
stop
();
}
/// Releases any resources used by this object.
///
/// Same as stop().
void
dispose
()
{
stop
();
}
///
/// Flings the timeline with an optional force (defaults to a critically
/// damped spring) and initial velocity. If velocity is positive, the
/// animation will complete, otherwise it will dismiss.
Future
fling
({
double
velocity:
1.0
,
Force
force
})
{
force
??=
kDefaultSpringForce
;
_direction
=
velocity
<
0.0
?
AnimationDirection
.
reverse
:
AnimationDirection
.
forward
;
return
_timeline
.
animateWith
(
force
.
release
(
progress
,
velocity
));
}
/// Starts running this animation in the forward direction, and
/// restarts the animation when it completes.
Future
repeat
({
double
min:
0.0
,
double
max:
1.0
,
Duration
period
})
{
period
??=
duration
;
return
_timeline
.
animateWith
(
new
_RepeatingSimulation
(
min
,
max
,
period
));
}
PerformanceStatus
_lastStatus
=
PerformanceStatus
.
dismissed
;
void
_checkStatusChanged
()
{
PerformanceStatus
currentStatus
=
status
;
if
(
currentStatus
!=
_lastStatus
)
notifyStatusListeners
(
status
);
_lastStatus
=
currentStatus
;
}
void
_updateCurveDirection
()
{
if
(
status
!=
_lastStatus
)
{
if
(
_lastStatus
==
PerformanceStatus
.
dismissed
||
_lastStatus
==
PerformanceStatus
.
completed
)
_curveDirection
=
_direction
;
}
}
Future
_animateTo
(
double
target
)
{
Duration
remainingDuration
=
duration
*
(
target
-
_timeline
.
value
).
abs
();
_timeline
.
stop
();
if
(
remainingDuration
==
Duration
.
ZERO
)
return
new
Future
.
value
();
return
_timeline
.
animateTo
(
target
,
duration:
remainingDuration
);
}
void
_tick
(
double
t
)
{
_updateCurveDirection
();
notifyListeners
();
_checkStatusChanged
();
}
String
toStringDetails
()
{
String
paused
=
_timeline
.
isAnimating
?
''
:
'; paused'
;
String
label
=
debugLabel
==
null
?
''
:
'; for
$debugLabel
'
;
String
more
=
super
.
toStringDetails
();
return
'
$more$paused$label
'
;
}
}
class
_RepeatingSimulation
extends
Simulation
{
_RepeatingSimulation
(
this
.
min
,
this
.
max
,
Duration
period
)
:
_periodInSeconds
=
period
.
inMicroseconds
/
Duration
.
MICROSECONDS_PER_SECOND
{
assert
(
_periodInSeconds
>
0.0
);
}
final
double
min
;
final
double
max
;
final
double
_periodInSeconds
;
double
x
(
double
timeInSeconds
)
{
assert
(
timeInSeconds
>=
0.0
);
final
double
t
=
(
timeInSeconds
/
_periodInSeconds
)
%
1.0
;
return
lerpDouble
(
min
,
max
,
t
);
}
double
dx
(
double
timeInSeconds
)
=>
1.0
;
bool
isDone
(
double
timeInSeconds
)
=>
false
;
}
// TODO(abarth): Rename Curve to UnitTransform and ACurve to Curve.
class
ACurve
extends
Animation
with
ProxyWatchableMixin
{
ACurve
({
this
.
parent
,
this
.
curve
,
this
.
reverseCurve
})
{
assert
(
parent
!=
null
);
assert
(
curve
!=
null
);
}
final
Animation
parent
;
/// The curve to use in the forward direction.
Curve
curve
;
/// The curve to use in the reverse direction.
///
/// If this field is null, uses [curve] in both directions.
Curve
reverseCurve
;
double
get
progress
{
final
bool
useForwardCurve
=
parent
.
curveDirection
==
AnimationDirection
.
forward
||
reverseCurve
==
null
;
Curve
activeCurve
=
useForwardCurve
?
curve
:
reverseCurve
;
double
t
=
parent
.
progress
;
if
(
activeCurve
==
null
)
return
t
;
if
(
t
==
0.0
||
t
==
1.0
)
{
assert
(
activeCurve
.
transform
(
t
).
round
()
==
t
);
return
t
;
}
return
activeCurve
.
transform
(
t
);
}
}
class
Tween
<
T
extends
dynamic
>
extends
Evaluatable
<
T
>
{
Tween
({
this
.
begin
,
this
.
end
})
{
assert
(
begin
!=
null
);
}
/// The value this variable has at the beginning of the animation.
T
begin
;
/// The value this variable has at the end of the animation.
T
end
;
/// Returns the value this variable has at the given animation clock value.
T
lerp
(
double
t
)
=>
begin
+
(
end
-
begin
)
*
t
;
T
evaluate
(
double
t
)
{
if
(
end
==
null
)
return
begin
;
if
(
t
==
0.0
)
return
begin
;
if
(
t
==
1.0
)
return
end
;
return
lerp
(
t
);
}
}
/// An animated variable containing a color.
///
/// This class specializes the interpolation of Tween<Color> to be
/// appropriate for colors.
class
ColorTween
extends
Tween
<
Color
>
{
ColorTween
({
Color
begin
,
Color
end
})
:
super
(
begin:
begin
,
end:
end
);
Color
lerp
(
double
t
)
=>
Color
.
lerp
(
begin
,
end
,
t
);
}
/// An animated variable containing a size.
///
/// This class specializes the interpolation of Tween<Size> to be
/// appropriate for rectangles.
class
SizeTween
extends
Tween
<
Size
>
{
SizeTween
({
Size
begin
,
Size
end
})
:
super
(
begin:
begin
,
end:
end
);
Size
lerp
(
double
t
)
=>
Size
.
lerp
(
begin
,
end
,
t
);
}
/// An animated variable containing a rectangle.
///
/// This class specializes the interpolation of Tween<Rect> to be
/// appropriate for rectangles.
class
RectTween
extends
Tween
<
Rect
>
{
RectTween
({
Rect
begin
,
Rect
end
})
:
super
(
begin:
begin
,
end:
end
);
Rect
lerp
(
double
t
)
=>
Rect
.
lerp
(
begin
,
end
,
t
);
}
/// An animated variable containing a int.
class
IntTween
extends
Tween
<
int
>
{
IntTween
({
int
begin
,
int
end
})
:
super
(
begin:
begin
,
end:
end
);
// The inherited lerp() function doesn't work with ints because it multiplies
// the begin and end types by a double, and int * double returns a double.
int
lerp
(
double
t
)
=>
(
begin
+
(
end
-
begin
)
*
t
).
round
();
}
packages/flutter/lib/src/widgets/transitions.dart
View file @
7f95d9b5
...
...
@@ -63,6 +63,55 @@ class _TransitionState extends State<TransitionComponent> {
}
}
abstract
class
AnimationWatchingComponent
extends
StatefulComponent
{
AnimationWatchingComponent
({
Key
key
,
this
.
watchable
})
:
super
(
key:
key
)
{
assert
(
watchable
!=
null
);
}
final
Watchable
watchable
;
Widget
build
(
BuildContext
context
);
_AnimationWatchingComponentState
createState
()
=>
new
_AnimationWatchingComponentState
();
void
debugFillDescription
(
List
<
String
>
description
)
{
super
.
debugFillDescription
(
description
);
description
.
add
(
'watchable:
$watchable
'
);
}
}
class
_AnimationWatchingComponentState
extends
State
<
AnimationWatchingComponent
>
{
void
initState
()
{
super
.
initState
();
config
.
watchable
.
addListener
(
_handleTick
);
}
void
didUpdateConfig
(
AnimationWatchingComponent
oldConfig
)
{
if
(
config
.
watchable
!=
oldConfig
.
watchable
)
{
oldConfig
.
watchable
.
removeListener
(
_handleTick
);
config
.
watchable
.
addListener
(
_handleTick
);
}
}
void
dispose
()
{
config
.
watchable
.
removeListener
(
_handleTick
);
super
.
dispose
();
}
void
_handleTick
()
{
setState
(()
{
// The watchable's state is our build state, and it changed already.
});
}
Widget
build
(
BuildContext
context
)
{
return
config
.
build
(
context
);
}
}
abstract
class
TransitionWithChild
extends
TransitionComponent
{
TransitionWithChild
({
Key
key
,
...
...
@@ -284,7 +333,6 @@ class PositionedTransition extends TransitionWithChild {
}
}
class
BuilderTransition
extends
TransitionComponent
{
BuilderTransition
({
Key
key
,
...
...
@@ -303,3 +351,17 @@ class BuilderTransition extends TransitionComponent {
return
builder
(
context
);
}
}
class
AnimationWatchingBuilder
extends
AnimationWatchingComponent
{
AnimationWatchingBuilder
({
Key
key
,
Watchable
watchable
,
this
.
builder
})
:
super
(
key:
key
,
watchable:
watchable
);
final
WidgetBuilder
builder
;
Widget
build
(
BuildContext
context
)
{
return
builder
(
context
);
}
}
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