Skip to content

Commit

Permalink
Update PopupRoute docs and add an example (#106948)
Browse files Browse the repository at this point in the history
  • Loading branch information
TahaTesser authored Jul 12, 2022
1 parent a8d0479 commit 66cd09d
Show file tree
Hide file tree
Showing 5 changed files with 178 additions and 11 deletions.
84 changes: 84 additions & 0 deletions examples/api/lib/widgets/routes/popup_route.0.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// 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.

// Flutter code sample for PopupRoute

import 'package:flutter/material.dart';

void main() => runApp(const PopupRouteApp());

class PopupRouteApp extends StatelessWidget {
const PopupRouteApp({super.key});

@override
Widget build(BuildContext context) {
return const MaterialApp(
home: PopupRouteExample(),
);
}
}

class PopupRouteExample extends StatelessWidget {
const PopupRouteExample({super.key});

@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: OutlinedButton(
onPressed: () {
/// This shows a dismissible dialog.
Navigator.of(context).push(DismissibleDialog<void>());
},
child: const Text('Open DismissibleDialog'),
),
),
);
}
}

class DismissibleDialog<T> extends PopupRoute<T> {
@override
Color? get barrierColor => Colors.black.withAlpha(0x50);

/// This allows the popup to be dismissed by tapping the scrim or by
/// pressing escape key on the keyboard.
@override
bool get barrierDismissible => true;

@override
String? get barrierLabel => 'Dismissible Dialog';

@override
Duration get transitionDuration => const Duration(milliseconds: 300);

@override
Widget buildPage(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation) {
return Center(
/// Provide DefaultTextStyle to ensure that the dialog's text style matches
/// the rest of the text in the app.
child: DefaultTextStyle(
style: Theme.of(context).textTheme.bodyMedium!,
/// `UnconstrainedBox` is used to make the dialog size itself
/// to fit to the size of the content.
child: UnconstrainedBox(
child: Container(
padding: const EdgeInsets.all(20.0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: Colors.white,
),
child: Column(
children: <Widget>[
Text('Dismissible Dialog', style: Theme.of(context).textTheme.headlineSmall),
const SizedBox(height: 20),
const Text('Tap in the scrim or press escape key to dismiss.'),
],
),
),
),
),
);
}
}
16 changes: 7 additions & 9 deletions examples/api/lib/widgets/routes/show_general_dialog.0.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,32 +6,30 @@

import 'package:flutter/material.dart';

void main() => runApp(const MyApp());
void main() => runApp(const GeneralDialogApp());

class MyApp extends StatelessWidget {
const MyApp({super.key});

static const String _title = 'Flutter Code Sample';
class GeneralDialogApp extends StatelessWidget {
const GeneralDialogApp({super.key});

@override
Widget build(BuildContext context) {
return const MaterialApp(
restorationScopeId: 'app',
title: _title,
home: MyStatelessWidget(),
home: GeneralDialogExample(),
);
}
}

class MyStatelessWidget extends StatelessWidget {
const MyStatelessWidget({super.key});
class GeneralDialogExample extends StatelessWidget {
const GeneralDialogExample({super.key});

@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: OutlinedButton(
onPressed: () {
/// This shows an alert dialog.
Navigator.of(context).restorablePush(_dialogBuilder);
},
child: const Text('Open Dialog'),
Expand Down
40 changes: 40 additions & 0 deletions examples/api/test/widgets/routes/popup_route.0_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// 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.

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_api_samples/widgets/routes/popup_route.0.dart' as example;
import 'package:flutter_test/flutter_test.dart';

void main() {
testWidgets('Dismiss dialog with tap on the scrim and escape key', (WidgetTester tester) async {
const String dialogText = 'Tap in the scrim or press escape key to dismiss.';

await tester.pumpWidget(
const example.PopupRouteApp(),
);

expect(find.text(dialogText), findsNothing);

// Tap on the button to show the dialog.
await tester.tap(find.byType(OutlinedButton));
await tester.pumpAndSettle();
expect(find.text(dialogText), findsOneWidget);

// Try to dismiss the dialog with a tap on the scrim.
await tester.tapAt(const Offset(10.0, 10.0));
await tester.pumpAndSettle();
expect(find.text(dialogText), findsNothing);

// Open the dialog again.
await tester.tap(find.byType(OutlinedButton));
await tester.pumpAndSettle();
expect(find.text(dialogText), findsOneWidget);

// Try to dismiss the dialog with the escape key.
await tester.sendKeyEvent(LogicalKeyboardKey.escape);
await tester.pumpAndSettle();
expect(find.text(dialogText), findsNothing);
});
}
29 changes: 29 additions & 0 deletions examples/api/test/widgets/routes/show_general_dialog.0_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// 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.

import 'package:flutter/material.dart';
import 'package:flutter_api_samples/widgets/routes/show_general_dialog.0.dart' as example;
import 'package:flutter_test/flutter_test.dart';

void main() {
testWidgets('Open and dismiss general dialog', (WidgetTester tester) async {
const String dialogText = 'Alert!';

await tester.pumpWidget(
const example.GeneralDialogApp(),
);

expect(find.text(dialogText), findsNothing);

// Tap on the button to show the dialog.
await tester.tap(find.byType(OutlinedButton));
await tester.pumpAndSettle();
expect(find.text(dialogText), findsOneWidget);

// Try to dismiss the dialog with a tap on the scrim.
await tester.tapAt(const Offset(10.0, 10.0));
await tester.pumpAndSettle();
expect(find.text(dialogText), findsNothing);
});
}
20 changes: 18 additions & 2 deletions packages/flutter/lib/src/widgets/routes.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1210,8 +1210,10 @@ 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.
///
/// If [barrierDismissible] is true, then tapping this barrier will cause the
/// current route to be popped (see [Navigator.pop]) with null as the value.
/// If [barrierDismissible] is true, then tapping this barrier, pressing
/// the escape key on the keyboard, or calling route popping functions
/// such as [Navigator.pop] will cause the current route to be popped
/// with null as the value.
///
/// If [barrierDismissible] is false, then tapping the barrier has no effect.
///
Expand All @@ -1226,6 +1228,7 @@ abstract class ModalRoute<T> extends TransitionRoute<T> with LocalHistoryRoute<T
///
/// See also:
///
/// * [Navigator.pop], which is used to dismiss the route.
/// * [barrierColor], which controls the color of the scrim for this route.
/// * [ModalBarrier], the widget that implements this feature.
/// {@endtemplate}
Expand Down Expand Up @@ -1691,6 +1694,19 @@ abstract class ModalRoute<T> extends TransitionRoute<T> with LocalHistoryRoute<T
}

/// A modal route that overlays a widget over the current route.
///
/// {@macro flutter.widgets.ModalRoute.barrierDismissible}
///
/// {@tool dartpad}
/// This example shows how to create a dialog box that is dismissible.
///
/// ** See code in examples/api/lib/widgets/routes/popup_route.0.dart **
/// {@end-tool}
///
/// See also:
///
/// * [ModalRoute], which is the base class for this class.
/// * [Navigator.pop], which is used to dismiss the route.
abstract class PopupRoute<T> extends ModalRoute<T> {
/// Initializes the [PopupRoute].
PopupRoute({
Expand Down

0 comments on commit 66cd09d

Please sign in to comment.