Update PopupRoute
docs and add an example (#106948)
This commit is contained in:
parent
a8d047923b
commit
66cd09dd82
84
examples/api/lib/widgets/routes/popup_route.0.dart
Normal file
84
examples/api/lib/widgets/routes/popup_route.0.dart
Normal file
@ -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.'),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -6,25 +6,22 @@
|
||||
|
||||
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) {
|
||||
@ -32,6 +29,7 @@ class MyStatelessWidget extends StatelessWidget {
|
||||
body: Center(
|
||||
child: OutlinedButton(
|
||||
onPressed: () {
|
||||
/// This shows an alert dialog.
|
||||
Navigator.of(context).restorablePush(_dialogBuilder);
|
||||
},
|
||||
child: const Text('Open Dialog'),
|
||||
|
40
examples/api/test/widgets/routes/popup_route.0_test.dart
Normal file
40
examples/api/test/widgets/routes/popup_route.0_test.dart
Normal file
@ -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);
|
||||
});
|
||||
}
|
@ -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);
|
||||
});
|
||||
}
|
@ -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.
|
||||
///
|
||||
@ -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}
|
||||
@ -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({
|
||||
|
Loading…
x
Reference in New Issue
Block a user