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
8f3805f5
Unverified
Commit
8f3805f5
authored
Aug 17, 2020
by
Ian Hickson
Committed by
GitHub
Aug 17, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Build routes even less. (#62588)
parent
90aad51d
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
182 additions
and
21 deletions
+182
-21
pages.dart
packages/flutter/lib/src/widgets/pages.dart
+12
-0
routes.dart
packages/flutter/lib/src/widgets/routes.dart
+31
-20
navigator_test.dart
packages/flutter/test/widgets/navigator_test.dart
+44
-1
page_route_builder_test.dart
packages/flutter/test/widgets/page_route_builder_test.dart
+95
-0
No files found.
packages/flutter/lib/src/widgets/pages.dart
View file @
8f3805f5
...
...
@@ -175,9 +175,21 @@ class TransitionBuilderPage<T> extends Page<T> {
final
bool
barrierDismissible
;
/// {@macro flutter.widgets.modalRoute.barrierColor}
///
/// See also:
///
/// * [barrierDismissible], which controls the behavior of the barrier when
/// tapped.
/// * [ModalBarrier], the widget that implements this feature.
final
Color
barrierColor
;
/// {@macro flutter.widgets.modalRoute.barrierLabel}
///
/// See also:
///
/// * [barrierDismissible], which controls the behavior of the barrier when
/// tapped.
/// * [ModalBarrier], the widget that implements this feature.
final
String
barrierLabel
;
/// {@macro flutter.widgets.modalRoute.maintainState}
...
...
packages/flutter/lib/src/widgets/routes.dart
View file @
8f3805f5
...
...
@@ -24,6 +24,7 @@ import 'transitions.dart';
// Examples can assume:
// dynamic routeObserver;
// NavigatorState navigator;
const
Color
_kTransparent
=
Color
(
0x00000000
);
...
...
@@ -193,7 +194,6 @@ abstract class TransitionRoute<T> extends OverlayRoute<T> {
}
break
;
}
changedInternalState
();
}
@override
...
...
@@ -201,16 +201,19 @@ abstract class TransitionRoute<T> extends OverlayRoute<T> {
assert
(!
_transitionCompleter
.
isCompleted
,
'Cannot install a
$runtimeType
after disposing it.'
);
_controller
=
createAnimationController
();
assert
(
_controller
!=
null
,
'
$runtimeType
.createAnimationController() returned null.'
);
_animation
=
createAnimation
();
_animation
=
createAnimation
()
..
addStatusListener
(
_handleStatusChanged
);
assert
(
_animation
!=
null
,
'
$runtimeType
.createAnimation() returned null.'
);
super
.
install
();
if
(
_animation
.
isCompleted
&&
overlayEntries
.
isNotEmpty
)
{
overlayEntries
.
first
.
opaque
=
opaque
;
}
}
@override
TickerFuture
didPush
()
{
assert
(
_controller
!=
null
,
'
$runtimeType
.didPush called before calling install() or after calling dispose().'
);
assert
(!
_transitionCompleter
.
isCompleted
,
'Cannot reuse a
$runtimeType
after disposing it.'
);
_didPushOrReplace
();
super
.
didPush
();
return
_controller
.
forward
();
}
...
...
@@ -219,7 +222,6 @@ abstract class TransitionRoute<T> extends OverlayRoute<T> {
void
didAdd
()
{
assert
(
_controller
!=
null
,
'
$runtimeType
.didPush called before calling install() or after calling dispose().'
);
assert
(!
_transitionCompleter
.
isCompleted
,
'Cannot reuse a
$runtimeType
after disposing it.'
);
_didPushOrReplace
();
super
.
didAdd
();
_controller
.
value
=
_controller
.
upperBound
;
}
...
...
@@ -230,19 +232,9 @@ abstract class TransitionRoute<T> extends OverlayRoute<T> {
assert
(!
_transitionCompleter
.
isCompleted
,
'Cannot reuse a
$runtimeType
after disposing it.'
);
if
(
oldRoute
is
TransitionRoute
)
_controller
.
value
=
oldRoute
.
_controller
.
value
;
_didPushOrReplace
();
super
.
didReplace
(
oldRoute
);
}
void
_didPushOrReplace
()
{
_animation
.
addStatusListener
(
_handleStatusChanged
);
// If the animation is already completed, _handleStatusChanged will not get
// a chance to set opaqueness of OverlayEntry.
if
(
_animation
.
isCompleted
&&
overlayEntries
.
isNotEmpty
)
{
overlayEntries
.
first
.
opaque
=
opaque
;
}
}
@override
bool
didPop
(
T
result
)
{
assert
(
_controller
!=
null
,
'
$runtimeType
.didPop called before calling install() or after calling dispose().'
);
...
...
@@ -878,7 +870,7 @@ abstract class ModalRoute<T> extends TransitionRoute<T> with LocalHistoryRoute<T
/// ```
///
/// The given [BuildContext] will be rebuilt if the state of the route changes
/// (specifically, if [isCurrent] or [canPop] change value).
///
while it is visible
(specifically, if [isCurrent] or [canPop] change value).
@optionalTypeArgs
static
ModalRoute
<
T
>
of
<
T
extends
Object
>(
BuildContext
context
)
{
final
_ModalScopeStatus
widget
=
context
.
dependOnInheritedWidgetOfExactType
<
_ModalScopeStatus
>();
...
...
@@ -958,7 +950,8 @@ abstract class ModalRoute<T> extends TransitionRoute<T> with LocalHistoryRoute<T
/// is not wrapped in any transition widgets.
///
/// The [buildTransitions] method, in contrast to [buildPage], is called each
/// time the [Route]'s state changes (e.g. the value of [canPop]).
/// time the [Route]'s state changes while it is visible (e.g. if the value of
/// [canPop] changes on the active route).
///
/// The [buildTransitions] method is typically used to define transitions
/// that animate the new topmost route's comings and goings. When the
...
...
@@ -1155,17 +1148,31 @@ abstract class ModalRoute<T> extends TransitionRoute<T> with LocalHistoryRoute<T
///
/// While the route is animating into position, the color is animated from
/// transparent to the specified color.
/// {@endtemplate}
///
/// If this getter would ever start returning a different color, the
/// [Route.changedInternalState] should be invoked so that the change can take
/// effect.
///
/// {@tool snippet}
///
/// It is safe to use `navigator.context` here. For example, to make
/// the barrier color use the theme's background color, one could say:
///
/// ```dart
/// Color get barrierColor => Theme.of(navigator.context).backgroundColor;
/// ```
///
/// The [Navigator] causes the [ModalRoute]'s modal barrier overlay entry
/// to rebuild any time its dependencies change.
///
/// {@end-tool}
///
/// See also:
///
/// * [barrierDismissible], which controls the behavior of the barrier when
/// tapped.
/// * [ModalBarrier], the widget that implements this feature.
/// {@endtemplate}
Color
get
barrierColor
;
/// {@template flutter.widgets.modalRoute.barrierLabel}
...
...
@@ -1180,6 +1187,7 @@ abstract class ModalRoute<T> extends TransitionRoute<T> with LocalHistoryRoute<T
///
/// For example, when a dialog is on the screen, the page below the dialog is
/// usually darkened by the modal barrier.
/// {@endtemplate}
///
/// If this getter would ever start returning a different label, the
/// [Route.changedInternalState] should be invoked so that the change can take
...
...
@@ -1190,7 +1198,6 @@ abstract class ModalRoute<T> extends TransitionRoute<T> with LocalHistoryRoute<T
/// * [barrierDismissible], which controls the behavior of the barrier when
/// tapped.
/// * [ModalBarrier], the widget that implements this feature.
/// {@endtemplate}
String
get
barrierLabel
;
/// The curve that is used for animating the modal barrier in and out.
...
...
@@ -1247,6 +1254,8 @@ abstract class ModalRoute<T> extends TransitionRoute<T> with LocalHistoryRoute<T
///
/// The modal barrier, if any, is not rendered if [offstage] is true (see
/// [barrierColor]).
///
/// Whenever this changes value, [changedInternalState] is called.
bool
get
offstage
=>
_offstage
;
bool
_offstage
=
false
;
set
offstage
(
bool
value
)
{
...
...
@@ -1257,6 +1266,7 @@ abstract class ModalRoute<T> extends TransitionRoute<T> with LocalHistoryRoute<T
});
_animationProxy
.
parent
=
_offstage
?
kAlwaysCompleteAnimation
:
super
.
animation
;
_secondaryAnimationProxy
.
parent
=
_offstage
?
kAlwaysDismissedAnimation
:
super
.
secondaryAnimation
;
changedInternalState
();
}
/// The build context for the subtree containing the primary content of this route.
...
...
@@ -1423,8 +1433,9 @@ abstract class ModalRoute<T> extends TransitionRoute<T> with LocalHistoryRoute<T
/// Whether this route can be popped.
///
/// When this changes, the route will rebuild, and any widgets that used
/// [ModalRoute.of] will be notified.
/// When this changes, if the route is visible, the route will
/// rebuild, and any widgets that used [ModalRoute.of] will be
/// notified.
bool
get
canPop
=>
!
isFirst
||
willHandlePopInternally
;
// Internals
...
...
packages/flutter/test/widgets/navigator_test.dart
View file @
8f3805f5
...
...
@@ -1208,7 +1208,50 @@ void main() {
expect
(
log
,
<
String
>[
'building B'
,
'building C'
,
'found C'
,
'building D'
]);
key
.
currentState
.
pop
<
void
>();
await
tester
.
pumpAndSettle
(
const
Duration
(
milliseconds:
10
));
expect
(
log
,
<
String
>[
'building B'
,
'building C'
,
'found C'
,
'building D'
,
'building C'
,
'found C'
]);
expect
(
log
,
<
String
>[
'building B'
,
'building C'
,
'found C'
,
'building D'
]);
});
testWidgets
(
'Routes don
\'
t rebuild just because their animations ended'
,
(
WidgetTester
tester
)
async
{
final
GlobalKey
<
NavigatorState
>
key
=
GlobalKey
<
NavigatorState
>();
final
List
<
String
>
log
=
<
String
>[];
Route
<
dynamic
>
nextRoute
=
PageRouteBuilder
<
int
>(
pageBuilder:
(
BuildContext
context
,
Animation
<
double
>
animation
,
Animation
<
double
>
secondaryAnimation
)
{
log
.
add
(
'building page 1 -
${ModalRoute.of(context).canPop}
'
);
return
const
Placeholder
();
},
);
await
tester
.
pumpWidget
(
MaterialApp
(
navigatorKey:
key
,
onGenerateRoute:
(
RouteSettings
settings
)
{
assert
(
nextRoute
!=
null
);
final
Route
<
dynamic
>
result
=
nextRoute
;
nextRoute
=
null
;
return
result
;
},
));
expect
(
log
,
<
String
>[
'building page 1 - false'
]);
key
.
currentState
.
pushReplacement
(
PageRouteBuilder
<
int
>(
pageBuilder:
(
BuildContext
context
,
Animation
<
double
>
animation
,
Animation
<
double
>
secondaryAnimation
)
{
log
.
add
(
'building page 2 -
${ModalRoute.of(context).canPop}
'
);
return
const
Placeholder
();
},
));
expect
(
log
,
<
String
>[
'building page 1 - false'
]);
await
tester
.
pump
();
expect
(
log
,
<
String
>[
'building page 1 - false'
,
'building page 2 - false'
]);
await
tester
.
pump
(
const
Duration
(
milliseconds:
150
));
expect
(
log
,
<
String
>[
'building page 1 - false'
,
'building page 2 - false'
]);
key
.
currentState
.
pushReplacement
(
PageRouteBuilder
<
int
>(
pageBuilder:
(
BuildContext
context
,
Animation
<
double
>
animation
,
Animation
<
double
>
secondaryAnimation
)
{
log
.
add
(
'building page 3 -
${ModalRoute.of(context).canPop}
'
);
return
const
Placeholder
();
},
));
expect
(
log
,
<
String
>[
'building page 1 - false'
,
'building page 2 - false'
]);
await
tester
.
pump
();
expect
(
log
,
<
String
>[
'building page 1 - false'
,
'building page 2 - false'
,
'building page 3 - false'
]);
await
tester
.
pump
(
const
Duration
(
milliseconds:
200
));
expect
(
log
,
<
String
>[
'building page 1 - false'
,
'building page 2 - false'
,
'building page 3 - false'
]);
});
testWidgets
(
'route semantics'
,
(
WidgetTester
tester
)
async
{
...
...
packages/flutter/test/widgets/page_route_builder_test.dart
0 → 100644
View file @
8f3805f5
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import
'package:flutter/material.dart'
;
import
'package:flutter/widgets.dart'
;
import
'package:flutter_test/flutter_test.dart'
;
class
TestPage
extends
StatelessWidget
{
@override
Widget
build
(
BuildContext
context
)
{
return
MaterialApp
(
title:
'Test'
,
theme:
ThemeData
(
primarySwatch:
Colors
.
blue
,
),
home:
HomePage
(),
);
}
}
class
HomePage
extends
StatefulWidget
{
@override
State
<
StatefulWidget
>
createState
()
=>
_HomePageState
();
}
class
_HomePageState
extends
State
<
HomePage
>
{
void
_presentModalPage
()
{
Navigator
.
of
(
context
).
push
(
PageRouteBuilder
<
void
>(
transitionDuration:
const
Duration
(
milliseconds:
300
),
barrierColor:
Colors
.
black54
,
opaque:
false
,
pageBuilder:
(
BuildContext
context
,
_
,
__
)
{
return
ModalPage
();
},
));
}
@override
Widget
build
(
BuildContext
context
)
{
return
Scaffold
(
body:
const
Center
(
child:
Text
(
'Test Home'
),
),
floatingActionButton:
FloatingActionButton
(
onPressed:
_presentModalPage
,
child:
const
Icon
(
Icons
.
add
),
),
);
}
}
class
ModalPage
extends
StatelessWidget
{
@override
Widget
build
(
BuildContext
context
)
{
return
Material
(
type:
MaterialType
.
transparency
,
child:
SafeArea
(
child:
Stack
(
children:
<
Widget
>[
InkWell
(
highlightColor:
Colors
.
transparent
,
splashColor:
Colors
.
transparent
,
onTap:
()
{
Navigator
.
of
(
context
).
pop
();
},
child:
const
SizedBox
.
expand
(),
),
Align
(
alignment:
Alignment
.
bottomCenter
,
child:
Container
(
height:
150
,
color:
Colors
.
teal
,
),
),
],
),
),
);
}
}
void
main
(
)
{
testWidgets
(
'Barriers show when using PageRouteBuilder'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
TestPage
());
await
tester
.
tap
(
find
.
byType
(
FloatingActionButton
));
await
tester
.
pumpAndSettle
();
await
expectLater
(
find
.
byType
(
TestPage
),
matchesGoldenFile
(
'page_route_builder.barrier.png'
),
);
});
}
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