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
822084b2
Commit
822084b2
authored
Oct 18, 2017
by
xster
Committed by
GitHub
Oct 18, 2017
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add a rootNavigator option to Navigator.of (#12580)
parent
964a138d
Changes
5
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
106 additions
and
3 deletions
+106
-3
dialog.dart
packages/flutter/lib/src/cupertino/dialog.dart
+3
-0
dialog.dart
packages/flutter/lib/src/material/dialog.dart
+1
-1
framework.dart
packages/flutter/lib/src/widgets/framework.dart
+24
-0
navigator.dart
packages/flutter/lib/src/widgets/navigator.dart
+11
-2
navigator_test.dart
packages/flutter/test/widgets/navigator_test.dart
+67
-0
No files found.
packages/flutter/lib/src/cupertino/dialog.dart
View file @
822084b2
...
...
@@ -53,6 +53,9 @@ const BoxDecoration _kCupertinoDialogBackFill = const BoxDecoration(
/// dialog. Rather than using this widget directly, consider using
/// [CupertinoAlertDialog], which implement a specific kind of dialog.
///
/// Push with `Navigator.of(..., rootNavigator: true)` when using with
/// [CupertinoTabScaffold] to ensure that the dialog appears above the tabs.
///
/// See also:
///
/// * [CupertinoAlertDialog], which is a dialog with title, contents, and
...
...
packages/flutter/lib/src/material/dialog.dart
View file @
822084b2
...
...
@@ -461,7 +461,7 @@ Future<T> showDialog<T>({
bool
barrierDismissible:
true
,
@required
Widget
child
,
})
{
return
Navigator
.
push
(
context
,
new
_DialogRoute
<
T
>(
return
Navigator
.
of
(
context
,
rootNavigator:
true
).
push
(
new
_DialogRoute
<
T
>(
child:
child
,
theme:
Theme
.
of
(
context
,
shadowThemeOnly:
true
),
barrierDismissible:
barrierDismissible
,
...
...
packages/flutter/lib/src/widgets/framework.dart
View file @
822084b2
...
...
@@ -2003,6 +2003,17 @@ abstract class BuildContext {
/// ```
State
ancestorStateOfType
(
TypeMatcher
matcher
);
/// Returns the [State] object of the furthest ancestor [StatefulWidget] widget
/// that matches the given [TypeMatcher].
///
/// Functions the same way as [ancestorStateOfType] but keeps visiting subsequent
/// ancestors until there are none of the type matching [TypeMatcher] remaining.
/// Then returns the last one found.
///
/// This operation is O(N) as well though N is the entire widget tree rather than
/// a subtree.
State
rootAncestorStateOfType
(
TypeMatcher
matcher
);
/// Returns the [RenderObject] object of the nearest ancestor [RenderObjectWidget] widget
/// that matches the given [TypeMatcher].
///
...
...
@@ -3245,6 +3256,19 @@ abstract class Element extends DiagnosticableTree implements BuildContext {
return
statefulAncestor
?.
state
;
}
@override
State
rootAncestorStateOfType
(
TypeMatcher
matcher
)
{
assert
(
_debugCheckStateIsActiveForAncestorLoopkup
());
Element
ancestor
=
_parent
;
StatefulElement
statefulAncestor
;
while
(
ancestor
!=
null
)
{
if
(
ancestor
is
StatefulElement
&&
matcher
.
check
(
ancestor
.
state
))
statefulAncestor
=
ancestor
;
ancestor
=
ancestor
.
_parent
;
}
return
statefulAncestor
?.
state
;
}
@override
RenderObject
ancestorRenderObjectOfType
(
TypeMatcher
matcher
)
{
assert
(
_debugCheckStateIsActiveForAncestorLoopkup
());
...
...
packages/flutter/lib/src/widgets/navigator.dart
View file @
822084b2
...
...
@@ -708,8 +708,17 @@ class Navigator extends StatefulWidget {
/// ..pop()
/// ..pushNamed('/settings');
/// ```
static
NavigatorState
of
(
BuildContext
context
)
{
final
NavigatorState
navigator
=
context
.
ancestorStateOfType
(
const
TypeMatcher
<
NavigatorState
>());
///
/// If `rootNavigator` is set to true, the state from the furthest instance of
/// this class is given instead. Useful for pushing contents above all subsequent
/// instances of [Navigator].
static
NavigatorState
of
(
BuildContext
context
,
{
bool
rootNavigator:
false
})
{
final
NavigatorState
navigator
=
rootNavigator
?
context
.
rootAncestorStateOfType
(
const
TypeMatcher
<
NavigatorState
>())
:
context
.
ancestorStateOfType
(
const
TypeMatcher
<
NavigatorState
>());
assert
(()
{
if
(
navigator
==
null
)
{
throw
new
FlutterError
(
...
...
packages/flutter/test/widgets/navigator_test.dart
View file @
822084b2
...
...
@@ -179,6 +179,73 @@ void main() {
expect
(
'
$exception
'
,
startsWith
(
'Navigator operation requested with a context'
));
});
testWidgets
(
'Navigator.of rootNavigator finds root Navigator'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
new
MaterialApp
(
home:
new
Material
(
child:
new
Column
(
children:
<
Widget
>[
const
SizedBox
(
height:
300.0
,
child:
const
Text
(
'Root page'
),
),
new
SizedBox
(
height:
300.0
,
child:
new
Navigator
(
onGenerateRoute:
(
RouteSettings
settings
)
{
if
(
settings
.
isInitialRoute
)
{
return
new
MaterialPageRoute
<
Null
>(
builder:
(
BuildContext
context
)
{
return
new
RaisedButton
(
child:
const
Text
(
'Next'
),
onPressed:
()
{
Navigator
.
of
(
context
).
push
(
new
MaterialPageRoute
<
Null
>(
builder:
(
BuildContext
context
)
{
return
new
RaisedButton
(
child:
const
Text
(
'Inner page'
),
onPressed:
()
{
Navigator
.
of
(
context
,
rootNavigator:
true
).
push
(
new
MaterialPageRoute
<
Null
>(
builder:
(
BuildContext
context
)
{
return
const
Text
(
'Dialog'
);
}
),
);
},
);
}
),
);
},
);
},
);
}
},
),
),
],
),
),
));
await
tester
.
tap
(
find
.
text
(
'Next'
));
await
tester
.
pump
();
await
tester
.
pump
(
const
Duration
(
milliseconds:
300
));
// Both elements are on screen.
expect
(
tester
.
getTopLeft
(
find
.
text
(
'Root page'
)).
dy
,
0.0
);
expect
(
tester
.
getTopLeft
(
find
.
text
(
'Inner page'
)).
dy
,
greaterThan
(
300.0
));
await
tester
.
tap
(
find
.
text
(
'Inner page'
));
await
tester
.
pump
();
await
tester
.
pump
(
const
Duration
(
milliseconds:
300
));
// Dialog is pushed to the whole page and is at the top of the screen, not
// inside the inner page.
expect
(
tester
.
getTopLeft
(
find
.
text
(
'Dialog'
)).
dy
,
0.0
);
});
testWidgets
(
'Gestures between push and build are ignored'
,
(
WidgetTester
tester
)
async
{
final
List
<
String
>
log
=
<
String
>[];
final
Map
<
String
,
WidgetBuilder
>
routes
=
<
String
,
WidgetBuilder
>{
...
...
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