Skip to content

Commit 536de5e

Browse files
authored
Update RouteObserver example and fix an error thrown (#141166)
fixes [`RouteObserver` example throws an error](flutter/flutter#141078) ### Description This updates the `RouteObserver` example from snippet to Dartpad example and fixes the error when running the code snippet
1 parent 1f3103e commit 536de5e

File tree

3 files changed

+169
-52
lines changed

3 files changed

+169
-52
lines changed
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
// Copyright 2014 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
import 'package:flutter/material.dart';
6+
7+
/// Flutter code sample for [RouteObserver].
8+
9+
final RouteObserver<ModalRoute<void>> routeObserver = RouteObserver<ModalRoute<void>>();
10+
11+
void main() {
12+
runApp(const RouteObserverApp());
13+
}
14+
15+
class RouteObserverApp extends StatelessWidget {
16+
const RouteObserverApp({super.key});
17+
18+
@override
19+
Widget build(BuildContext context) {
20+
return MaterialApp(
21+
navigatorObservers: <NavigatorObserver>[ routeObserver ],
22+
home: const RouteObserverExample(),
23+
);
24+
}
25+
}
26+
27+
class RouteObserverExample extends StatefulWidget {
28+
const RouteObserverExample({super.key});
29+
30+
@override
31+
State<RouteObserverExample> createState() => _RouteObserverExampleState();
32+
}
33+
34+
class _RouteObserverExampleState extends State<RouteObserverExample> with RouteAware {
35+
List<String> log = <String>[];
36+
37+
@override
38+
void didChangeDependencies() {
39+
super.didChangeDependencies();
40+
routeObserver.subscribe(this, ModalRoute.of(context)!);
41+
}
42+
43+
@override
44+
void dispose() {
45+
routeObserver.unsubscribe(this);
46+
super.dispose();
47+
}
48+
49+
@override
50+
void didPush() {
51+
// Route was pushed onto navigator and is now the topmost route.
52+
log.add('didPush');
53+
}
54+
55+
@override
56+
void didPopNext() {
57+
// Covering route was popped off the navigator.
58+
log.add('didPopNext');
59+
}
60+
61+
@override
62+
Widget build(BuildContext context) {
63+
return Scaffold(
64+
body: Center(
65+
child: Column(
66+
mainAxisSize: MainAxisSize.min,
67+
children: <Widget>[
68+
Text(
69+
'RouteObserver log:',
70+
style: Theme.of(context).textTheme.headlineSmall,
71+
),
72+
ConstrainedBox(
73+
constraints: const BoxConstraints(maxHeight: 300.0),
74+
child: ListView.builder(
75+
itemCount: log.length,
76+
itemBuilder: (BuildContext context, int index) {
77+
if (log.isEmpty) {
78+
return const SizedBox.shrink();
79+
}
80+
return Text(
81+
log[index],
82+
textAlign: TextAlign.center,
83+
);
84+
},
85+
),
86+
),
87+
OutlinedButton(
88+
onPressed: () {
89+
Navigator.of(context).push<void>(
90+
MaterialPageRoute<void>(
91+
builder: (BuildContext context) => const NextPage(),
92+
),
93+
);
94+
},
95+
child: const Text('Go to next page'),
96+
),
97+
],
98+
),
99+
),
100+
);
101+
}
102+
}
103+
104+
class NextPage extends StatelessWidget {
105+
const NextPage({super.key});
106+
107+
@override
108+
Widget build(BuildContext context) {
109+
return Scaffold(
110+
body: Center(
111+
child: FilledButton(
112+
onPressed: () {
113+
Navigator.of(context).pop();
114+
},
115+
child: const Text('Go back to RouteAware page'),
116+
)
117+
),
118+
);
119+
}
120+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// Copyright 2014 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
import 'package:flutter_api_samples/widgets/routes/route_observer.0.dart' as example;
6+
import 'package:flutter_test/flutter_test.dart';
7+
8+
void main() {
9+
testWidgets('RouteObserver notifies RouteAware widget', (WidgetTester tester) async {
10+
await tester.pumpWidget(
11+
const example.RouteObserverApp(),
12+
);
13+
14+
// Check the initial RouteObserver logs.
15+
expect(find.text('didPush'), findsOneWidget);
16+
17+
// Tap on the button to push a new route.
18+
await tester.tap(find.text('Go to next page'));
19+
await tester.pumpAndSettle();
20+
21+
// Tap on the button to go back to the previous route.
22+
await tester.tap(find.text('Go back to RouteAware page'));
23+
await tester.pumpAndSettle();
24+
25+
// Check the RouteObserver logs after the route is popped.
26+
expect(find.text('didPush'), findsOneWidget);
27+
expect(find.text('didPopNext'), findsOneWidget);
28+
29+
// Tap on the button to push a new route again.
30+
await tester.tap(find.text('Go to next page'));
31+
await tester.pumpAndSettle();
32+
33+
// Tap on the button to go back to the previous route again.
34+
await tester.tap(find.text('Go back to RouteAware page'));
35+
await tester.pumpAndSettle();
36+
37+
// Check the RouteObserver logs after the route is popped again.
38+
expect(find.text('didPush'), findsOneWidget);
39+
expect(find.text('didPopNext'), findsNWidgets(2));
40+
});
41+
}

packages/flutter/lib/src/widgets/routes.dart

Lines changed: 8 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1910,60 +1910,16 @@ abstract class PopupRoute<T> extends ModalRoute<T> {
19101910
/// than only specific subtypes. For example, to watch for all [ModalRoute]
19111911
/// variants, the `RouteObserver<ModalRoute<dynamic>>` type may be used.
19121912
///
1913-
/// {@tool snippet}
1914-
///
1915-
/// To make a [StatefulWidget] aware of its current [Route] state, implement
1916-
/// [RouteAware] in its [State] and subscribe it to a [RouteObserver]:
1917-
///
1918-
/// ```dart
1919-
/// // Register the RouteObserver as a navigation observer.
1920-
/// final RouteObserver<ModalRoute<void>> routeObserver = RouteObserver<ModalRoute<void>>();
1921-
///
1922-
/// void main() {
1923-
/// runApp(MaterialApp(
1924-
/// home: Container(),
1925-
/// navigatorObservers: <RouteObserver<ModalRoute<void>>>[ routeObserver ],
1926-
/// ));
1927-
/// }
1928-
///
1929-
/// class RouteAwareWidget extends StatefulWidget {
1930-
/// const RouteAwareWidget({super.key});
1931-
///
1932-
/// @override
1933-
/// State<RouteAwareWidget> createState() => RouteAwareWidgetState();
1934-
/// }
1935-
///
1936-
/// // Implement RouteAware in a widget's state and subscribe it to the RouteObserver.
1937-
/// class RouteAwareWidgetState extends State<RouteAwareWidget> with RouteAware {
1938-
///
1939-
/// @override
1940-
/// void didChangeDependencies() {
1941-
/// super.didChangeDependencies();
1942-
/// routeObserver.subscribe(this, ModalRoute.of(context)!);
1943-
/// }
1944-
///
1945-
/// @override
1946-
/// void dispose() {
1947-
/// routeObserver.unsubscribe(this);
1948-
/// super.dispose();
1949-
/// }
1950-
///
1951-
/// @override
1952-
/// void didPush() {
1953-
/// // Route was pushed onto navigator and is now topmost route.
1954-
/// }
1955-
///
1956-
/// @override
1957-
/// void didPopNext() {
1958-
/// // Covering route was popped off the navigator.
1959-
/// }
1960-
///
1961-
/// @override
1962-
/// Widget build(BuildContext context) => Container();
1913+
/// {@tool dartpad}
1914+
/// This example demonstrates how to implement a [RouteObserver] that notifies
1915+
/// [RouteAware] widget of changes to the state of their [Route].
19631916
///
1964-
/// }
1965-
/// ```
1917+
/// ** See code in examples/api/lib/widgets/routes/route_observer.0.dart **
19661918
/// {@end-tool}
1919+
///
1920+
/// See also:
1921+
/// * [RouteAware], this is used with [RouteObserver] to make a widget aware
1922+
/// of changes to the [Navigator]'s session history.
19671923
class RouteObserver<R extends Route<dynamic>> extends NavigatorObserver {
19681924
final Map<R, Set<RouteAware>> _listeners = <R, Set<RouteAware>>{};
19691925

0 commit comments

Comments
 (0)