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
d3d61988
Commit
d3d61988
authored
Sep 22, 2017
by
Hans Muller
Committed by
GitHub
Sep 22, 2017
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Make the Hero transition animation configurable (#12215)
parent
fde26cd1
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
222 additions
and
2 deletions
+222
-2
arc.dart
packages/flutter/lib/src/material/arc.dart
+90
-0
heroes.dart
packages/flutter/lib/src/widgets/heroes.dart
+17
-2
heroes_test.dart
packages/flutter/test/widgets/heroes_test.dart
+115
-0
No files found.
packages/flutter/lib/src/material/arc.dart
View file @
d3d61988
...
...
@@ -221,9 +221,13 @@ T _maxBy<T>(Iterable<T> input, _KeyFunc<T> keyFunc) {
///
/// See also:
///
/// * [MaterialRectCenterArcTween], which interpolates a rect along a circular
/// arc between the begin and end [Rect]'s centers.
/// * [Tween], for a discussion on how to use interpolation objects.
/// * [MaterialPointArcTween], the analogue for [Offset] interporation.
/// * [RectTween], which does a linear rectangle interpolation.
/// * [Hero.createRectTween], which can be used to specify the tween that defines
/// a hero's path.
class
MaterialRectArcTween
extends
RectTween
{
/// Creates a [Tween] for animating [Rect]s along a circular arc.
///
...
...
@@ -323,3 +327,89 @@ class MaterialRectArcTween extends RectTween {
return
'
$runtimeType
(
$begin
\
u2192
$end
; beginArc=
$beginArc
, endArc=
$endArc
)'
;
}
}
/// A [Tween] that interpolates a [Rect] by moving it along a circular
/// arc from [begin.center] to [end.center] while interpoloting the rectangle's
/// width and height.
///
/// The arc that defines that center of the interpolated rectangle as it morphs
/// from [begin] to [end] is a [MaterialPointArcTween].
///
/// See also:
///
/// * [MaterialRectArcTween], A [Tween] that interpolates a [Rect] by having
/// its opposite corners follow circular arcs.
/// * [Tween], for a discussion on how to use interpolation objects.
/// * [MaterialPointArcTween], the analogue for [Offset] interporation.
/// * [RectTween], which does a linear rectangle interpolation.
/// * [Hero.createRectTween], which can be used to specify the tween that defines
/// a hero's path.
class
MaterialRectCenterArcTween
extends
RectTween
{
/// Creates a [Tween] for animating [Rect]s along a circular arc.
///
/// The [begin] and [end] properties must be non-null before the tween is
/// first used, but the arguments can be null if the values are going to be
/// filled in later.
MaterialRectCenterArcTween
({
Rect
begin
,
Rect
end
,
})
:
super
(
begin:
begin
,
end:
end
);
bool
_dirty
=
true
;
void
_initialize
()
{
assert
(
begin
!=
null
);
assert
(
end
!=
null
);
_centerArc
=
new
MaterialPointArcTween
(
begin:
begin
.
center
,
end:
end
.
center
,
);
_dirty
=
false
;
}
/// If [begin] and [end] are non-null, returns a tween that interpolates
/// along a circular arc between [begin.center] and [end.center].
MaterialPointArcTween
get
centerArc
{
if
(
begin
==
null
||
end
==
null
)
return
null
;
if
(
_dirty
)
_initialize
();
return
_centerArc
;
}
MaterialPointArcTween
_centerArc
;
@override
set
begin
(
Rect
value
)
{
if
(
value
!=
begin
)
{
super
.
begin
=
value
;
_dirty
=
true
;
}
}
@override
set
end
(
Rect
value
)
{
if
(
value
!=
end
)
{
super
.
end
=
value
;
_dirty
=
true
;
}
}
@override
Rect
lerp
(
double
t
)
{
if
(
_dirty
)
_initialize
();
if
(
t
==
0.0
)
return
begin
;
if
(
t
==
1.0
)
return
end
;
final
Offset
center
=
_centerArc
.
lerp
(
t
);
final
double
width
=
lerpDouble
(
begin
.
width
,
end
.
width
,
t
);
final
double
height
=
lerpDouble
(
begin
.
height
,
end
.
height
,
t
);
return
new
Rect
.
fromLTWH
(
center
.
dx
-
width
/
2.0
,
center
.
dy
-
height
/
2.0
,
width
,
height
);
}
@override
String
toString
()
{
return
'
$runtimeType
(
$begin
\
u2192
$end
; centerArc=
$centerArc
)'
;
}
}
packages/flutter/lib/src/widgets/heroes.dart
View file @
d3d61988
...
...
@@ -80,6 +80,7 @@ class Hero extends StatefulWidget {
const
Hero
({
Key
key
,
@required
this
.
tag
,
this
.
createRectTween
,
@required
this
.
child
,
})
:
assert
(
tag
!=
null
),
assert
(
child
!=
null
),
...
...
@@ -90,6 +91,19 @@ class Hero extends StatefulWidget {
/// a hero animation will be triggered.
final
Object
tag
;
/// Defines how the destination hero's bounds change as it flies from the starting
/// route to the destination route.
///
/// A hero flight begins with the destination hero's [child] aligned with the
/// starting hero's child. The [RectTween] returned by this callback is used
/// to compute the hero's bounds as the flight animation's value goes from 0.0
/// to 1.0.
///
/// If this property is null, the default, then the value of
/// [HeroController.createRectTween] is used. The [HeroController] created by
/// [MaterialApp] creates a [MaterialArcRectTween].
final
CreateRectTween
createRectTween
;
/// The widget subtree that will "fly" from one route to another during a
/// [Navigator] push or pop transition.
///
...
...
@@ -230,8 +244,9 @@ class _HeroFlight {
bool
_aborted
=
false
;
RectTween
_doCreateRectTween
(
Rect
begin
,
Rect
end
)
{
if
(
manifest
.
createRectTween
!=
null
)
return
manifest
.
createRectTween
(
begin
,
end
);
final
CreateRectTween
createRectTween
=
manifest
.
toHero
.
widget
.
createRectTween
??
manifest
.
createRectTween
;
if
(
createRectTween
!=
null
)
return
createRectTween
(
begin
,
end
);
return
new
RectTween
(
begin:
begin
,
end:
end
);
}
...
...
packages/flutter/test/widgets/heroes_test.dart
View file @
d3d61988
...
...
@@ -1005,4 +1005,119 @@ void main() {
expect
(
find
.
text
(
'456'
),
findsOneWidget
);
});
testWidgets
(
'Hero createRectTween'
,
(
WidgetTester
tester
)
async
{
RectTween
createRectTween
(
Rect
begin
,
Rect
end
)
{
return
new
MaterialRectCenterArcTween
(
begin:
begin
,
end:
end
);
}
final
Map
<
String
,
WidgetBuilder
>
createRectTweenHeroRoutes
=
<
String
,
WidgetBuilder
>{
'/'
:
(
BuildContext
context
)
=>
new
Material
(
child:
new
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
<
Widget
>[
new
Hero
(
tag:
'a'
,
createRectTween:
createRectTween
,
child:
new
Container
(
height:
100.0
,
width:
100.0
,
key:
firstKey
),
),
new
FlatButton
(
child:
const
Text
(
'two'
),
onPressed:
()
{
Navigator
.
pushNamed
(
context
,
'/two'
);
}
),
]
)
),
'/two'
:
(
BuildContext
context
)
=>
new
Material
(
child:
new
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
center
,
children:
<
Widget
>[
new
SizedBox
(
height:
200.0
,
child:
new
FlatButton
(
child:
const
Text
(
'pop'
),
onPressed:
()
{
Navigator
.
pop
(
context
);
}
),
),
new
Hero
(
tag:
'a'
,
createRectTween:
createRectTween
,
child:
new
Container
(
height:
200.0
,
width:
100.0
,
key:
secondKey
),
),
],
),
),
};
await
tester
.
pumpWidget
(
new
MaterialApp
(
routes:
createRectTweenHeroRoutes
));
expect
(
tester
.
getCenter
(
find
.
byKey
(
firstKey
)),
const
Offset
(
50.0
,
50.0
));
final
double
epsilon
=
0.001
;
final
Duration
duration
=
const
Duration
(
milliseconds:
300
);
final
Curve
curve
=
Curves
.
fastOutSlowIn
;
final
MaterialPointArcTween
pushCenterTween
=
new
MaterialPointArcTween
(
begin:
const
Offset
(
50.0
,
50.0
),
end:
const
Offset
(
400.0
,
300.0
),
);
await
tester
.
tap
(
find
.
text
(
'two'
));
await
tester
.
pump
();
// begin navigation
// Verify that the center of the secondKey Hero flies along the
// pushCenterTween arc for the push /two flight.
await
tester
.
pump
();
expect
(
tester
.
getCenter
(
find
.
byKey
(
secondKey
)),
const
Offset
(
50.0
,
50.0
));
await
tester
.
pump
(
duration
*
0.25
);
Offset
actualHeroCenter
=
tester
.
getCenter
(
find
.
byKey
(
secondKey
));
Offset
predictedHeroCenter
=
pushCenterTween
.
lerp
(
curve
.
transform
(
0.25
));
expect
((
actualHeroCenter
-
predictedHeroCenter
).
distance
,
closeTo
(
0.0
,
epsilon
));
await
tester
.
pump
(
duration
*
0.25
);
actualHeroCenter
=
tester
.
getCenter
(
find
.
byKey
(
secondKey
));
predictedHeroCenter
=
pushCenterTween
.
lerp
(
curve
.
transform
(
0.5
));
expect
((
actualHeroCenter
-
predictedHeroCenter
).
distance
,
closeTo
(
0.0
,
epsilon
));
await
tester
.
pump
(
duration
*
0.25
);
actualHeroCenter
=
tester
.
getCenter
(
find
.
byKey
(
secondKey
));
predictedHeroCenter
=
pushCenterTween
.
lerp
(
curve
.
transform
(
0.75
));
expect
((
actualHeroCenter
-
predictedHeroCenter
).
distance
,
closeTo
(
0.0
,
epsilon
));
await
tester
.
pumpAndSettle
();
expect
(
tester
.
getCenter
(
find
.
byKey
(
secondKey
)),
const
Offset
(
400.0
,
300.0
));
// Verify that the center of the firstKey Hero flies along the
// pushCenterTween arc for the pop /two flight.
await
tester
.
tap
(
find
.
text
(
'pop'
));
await
tester
.
pump
();
// begin navigation
final
MaterialPointArcTween
popCenterTween
=
new
MaterialPointArcTween
(
begin:
const
Offset
(
400.0
,
300.0
),
end:
const
Offset
(
50.0
,
50.0
),
);
await
tester
.
pump
();
expect
(
tester
.
getCenter
(
find
.
byKey
(
firstKey
)),
const
Offset
(
400.0
,
300.0
));
await
tester
.
pump
(
duration
*
0.25
);
actualHeroCenter
=
tester
.
getCenter
(
find
.
byKey
(
firstKey
));
predictedHeroCenter
=
popCenterTween
.
lerp
(
curve
.
flipped
.
transform
(
0.25
));
expect
((
actualHeroCenter
-
predictedHeroCenter
).
distance
,
closeTo
(
0.0
,
epsilon
));
await
tester
.
pump
(
duration
*
0.25
);
actualHeroCenter
=
tester
.
getCenter
(
find
.
byKey
(
firstKey
));
predictedHeroCenter
=
popCenterTween
.
lerp
(
curve
.
flipped
.
transform
(
0.5
));
expect
((
actualHeroCenter
-
predictedHeroCenter
).
distance
,
closeTo
(
0.0
,
epsilon
));
await
tester
.
pump
(
duration
*
0.25
);
actualHeroCenter
=
tester
.
getCenter
(
find
.
byKey
(
firstKey
));
predictedHeroCenter
=
popCenterTween
.
lerp
(
curve
.
flipped
.
transform
(
0.75
));
expect
((
actualHeroCenter
-
predictedHeroCenter
).
distance
,
closeTo
(
0.0
,
epsilon
));
await
tester
.
pumpAndSettle
();
expect
(
tester
.
getCenter
(
find
.
byKey
(
firstKey
)),
const
Offset
(
50.0
,
50.0
));
});
}
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