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
731e9819
Unverified
Commit
731e9819
authored
Jun 14, 2019
by
LongCatIsLooong
Committed by
GitHub
Jun 14, 2019
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Allow "from" hero state to survive hero animation in a push transition (#32842)
parent
d310d31d
Changes
3
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
325 additions
and
36 deletions
+325
-36
nav_bar.dart
packages/flutter/lib/src/cupertino/nav_bar.dart
+2
-1
heroes.dart
packages/flutter/lib/src/widgets/heroes.dart
+80
-20
heroes_test.dart
packages/flutter/test/widgets/heroes_test.dart
+243
-15
No files found.
packages/flutter/lib/src/cupertino/nav_bar.dart
View file @
731e9819
...
@@ -2174,8 +2174,9 @@ CreateRectTween _linearTranslateWithLargestRectSizeTween = (Rect begin, Rect end
...
@@ -2174,8 +2174,9 @@ CreateRectTween _linearTranslateWithLargestRectSizeTween = (Rect begin, Rect end
);
);
};
};
final
Transition
Builder
_navBarHeroLaunchPadBuilder
=
(
final
HeroPlaceholder
Builder
_navBarHeroLaunchPadBuilder
=
(
BuildContext
context
,
BuildContext
context
,
Size
heroSize
,
Widget
child
,
Widget
child
,
)
{
)
{
assert
(
child
is
_TransitionableNavigationBar
);
assert
(
child
is
_TransitionableNavigationBar
);
...
...
packages/flutter/lib/src/widgets/heroes.dart
View file @
731e9819
...
@@ -11,6 +11,7 @@ import 'navigator.dart';
...
@@ -11,6 +11,7 @@ import 'navigator.dart';
import
'overlay.dart'
;
import
'overlay.dart'
;
import
'pages.dart'
;
import
'pages.dart'
;
import
'routes.dart'
;
import
'routes.dart'
;
import
'ticker_provider.dart'
show
TickerMode
;
import
'transitions.dart'
;
import
'transitions.dart'
;
/// Signature for a function that takes two [Rect] instances and returns a
/// Signature for a function that takes two [Rect] instances and returns a
...
@@ -21,6 +22,22 @@ import 'transitions.dart';
...
@@ -21,6 +22,22 @@ import 'transitions.dart';
/// [MaterialRectArcTween].
/// [MaterialRectArcTween].
typedef
CreateRectTween
=
Tween
<
Rect
>
Function
(
Rect
begin
,
Rect
end
);
typedef
CreateRectTween
=
Tween
<
Rect
>
Function
(
Rect
begin
,
Rect
end
);
/// Signature for a function that builds a [Hero] placeholder widget given a
/// child and a [Size].
///
/// The child can optionally be part of the returned widget tree. The returned
/// widget should typically be constrained to [heroSize], if it doesn't do so
/// implicitly.
///
/// See also:
/// * [TransitionBuilder], which is similar but only takes a [BuildContext]
/// and a child widget.
typedef
HeroPlaceholderBuilder
=
Widget
Function
(
BuildContext
context
,
Size
heroSize
,
Widget
child
,
);
/// A function that lets [Hero]es self supply a [Widget] that is shown during the
/// A function that lets [Hero]es self supply a [Widget] that is shown during the
/// hero's flight from one route to another instead of default (which is to
/// hero's flight from one route to another instead of default (which is to
/// show the destination route's instance of the Hero).
/// show the destination route's instance of the Hero).
...
@@ -189,13 +206,30 @@ class Hero extends StatefulWidget {
...
@@ -189,13 +206,30 @@ class Hero extends StatefulWidget {
///
///
/// If none is provided, the destination route's Hero child is shown in-flight
/// If none is provided, the destination route's Hero child is shown in-flight
/// by default.
/// by default.
///
/// ## Limitations
///
/// If a widget built by [flightShuttleBuilder] takes part in a [Navigator]
/// push transition, that widget or its descendants must not have any
/// [GlobalKey] that is used in the source Hero's descendant widgets. That is
/// because both subtrees will be included in the widget tree during the Hero
/// flight animation, and [GlobalKey]s must be unique across the entire widget
/// tree.
///
/// If the said [GlobalKey] is essential to your application, consider providing
/// a custom [placeholderBuilder] for the source Hero, to avoid the [GlobalKey]
/// collision, such as a builder that builds an empty [SizedBox], keeping the
/// Hero [child]'s original size.
final
HeroFlightShuttleBuilder
flightShuttleBuilder
;
final
HeroFlightShuttleBuilder
flightShuttleBuilder
;
/// Placeholder widget left in place as the Hero's child once the flight takes off.
/// Placeholder widget left in place as the Hero's [child] once the flight takes
/// off.
///
///
/// By default, an empty SizedBox keeping the Hero child's original size is
/// By default the placeholder widget is an empty [SizedBox] keeping the Hero
/// left in place once the Hero shuttle has taken flight.
/// child's original size, unless this Hero is a source Hero of a [Navigator]
final
TransitionBuilder
placeholderBuilder
;
/// push transition, in which case [child] will be a descendant of the placeholder
/// and will be kept [Offstage] during the Hero's flight.
final
HeroPlaceholderBuilder
placeholderBuilder
;
/// Whether to perform the hero transition if the [PageRoute] transition was
/// Whether to perform the hero transition if the [PageRoute] transition was
/// triggered by a user gesture, such as a back swipe on iOS.
/// triggered by a user gesture, such as a back swipe on iOS.
...
@@ -285,8 +319,24 @@ class Hero extends StatefulWidget {
...
@@ -285,8 +319,24 @@ class Hero extends StatefulWidget {
class
_HeroState
extends
State
<
Hero
>
{
class
_HeroState
extends
State
<
Hero
>
{
final
GlobalKey
_key
=
GlobalKey
();
final
GlobalKey
_key
=
GlobalKey
();
Size
_placeholderSize
;
Size
_placeholderSize
;
// Whether the placeholder widget should wrap the hero's child widget as its
void
startFlight
()
{
// own child, when `_placeholderSize` is non-null (i.e. the hero is currently
// in its flight animation). See `startFlight`.
bool
_shouldIncludeChild
=
true
;
// The `shouldIncludeChildInPlaceholder` flag dictates if the child widget of
// this hero should be included in the placeholder widget as a descendant.
//
// When a new hero flight animation takes place, a placeholder widget
// needs to be built to replace the original hero widget. When
// `shouldIncludeChildInPlaceholder` is set to true and `widget.placeholderBuilder`
// is null, the placeholder widget will include the original hero's child
// widget as a descendant, allowing the orignal element tree to be preserved.
//
// It is typically set to true for the *from* hero in a push transition,
// and false otherwise.
void
startFlight
({
bool
shouldIncludedChildInPlaceholder
=
false
})
{
_shouldIncludeChild
=
shouldIncludedChildInPlaceholder
;
assert
(
mounted
);
assert
(
mounted
);
final
RenderBox
box
=
context
.
findRenderObject
();
final
RenderBox
box
=
context
.
findRenderObject
();
assert
(
box
!=
null
&&
box
.
hasSize
);
assert
(
box
!=
null
&&
box
.
hasSize
);
...
@@ -310,19 +360,29 @@ class _HeroState extends State<Hero> {
...
@@ -310,19 +360,29 @@ class _HeroState extends State<Hero> {
'A Hero widget cannot be the descendant of another Hero widget.'
'A Hero widget cannot be the descendant of another Hero widget.'
);
);
if
(
_placeholderSize
!=
null
)
{
final
bool
isHeroInFlight
=
_placeholderSize
!=
null
;
if
(
widget
.
placeholderBuilder
==
null
)
{
return
SizedBox
(
if
(
isHeroInFlight
&&
widget
.
placeholderBuilder
!=
null
)
{
width:
_placeholderSize
.
width
,
return
widget
.
placeholderBuilder
(
context
,
_placeholderSize
,
widget
.
child
);
height:
_placeholderSize
.
height
,
);
}
else
{
return
widget
.
placeholderBuilder
(
context
,
widget
.
child
);
}
}
}
return
KeyedSubtree
(
key:
_key
,
if
(
isHeroInFlight
&&
!
_shouldIncludeChild
)
{
child:
widget
.
child
,
return
SizedBox
(
width:
_placeholderSize
.
width
,
height:
_placeholderSize
.
height
,
);
}
return
SizedBox
(
width:
_placeholderSize
?.
width
,
height:
_placeholderSize
?.
height
,
child:
Offstage
(
offstage:
isHeroInFlight
,
child:
TickerMode
(
enabled:
!
isHeroInFlight
,
child:
KeyedSubtree
(
key:
_key
,
child:
widget
.
child
),
)
),
);
);
}
}
}
}
...
@@ -496,7 +556,7 @@ class _HeroFlight {
...
@@ -496,7 +556,7 @@ class _HeroFlight {
else
else
_proxyAnimation
.
parent
=
manifest
.
animation
;
_proxyAnimation
.
parent
=
manifest
.
animation
;
manifest
.
fromHero
.
startFlight
();
manifest
.
fromHero
.
startFlight
(
shouldIncludedChildInPlaceholder:
manifest
.
type
==
HeroFlightDirection
.
push
);
manifest
.
toHero
.
startFlight
();
manifest
.
toHero
.
startFlight
();
heroRectTween
=
_doCreateRectTween
(
heroRectTween
=
_doCreateRectTween
(
...
@@ -574,7 +634,7 @@ class _HeroFlight {
...
@@ -574,7 +634,7 @@ class _HeroFlight {
manifest
.
toHero
.
endFlight
();
manifest
.
toHero
.
endFlight
();
// Let the heroes in each of the routes rebuild with their placeholders.
// Let the heroes in each of the routes rebuild with their placeholders.
newManifest
.
fromHero
.
startFlight
();
newManifest
.
fromHero
.
startFlight
(
shouldIncludedChildInPlaceholder:
newManifest
.
type
==
HeroFlightDirection
.
push
);
newManifest
.
toHero
.
startFlight
();
newManifest
.
toHero
.
startFlight
();
// Let the transition overlay on top of the routes also rebuild since
// Let the transition overlay on top of the routes also rebuild since
...
...
packages/flutter/test/widgets/heroes_test.dart
View file @
731e9819
This diff is collapsed.
Click to expand it.
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