Add Dialog.fullscreen
and example (#112261)
This commit is contained in:
parent
c66049fcef
commit
fd6997f07a
@ -120,6 +120,7 @@ Future<void> main(List<String> args) async {
|
||||
ButtonTemplate('md.comp.text-button', 'TextButton', '$materialLib/text_button.dart', tokens).updateFile();
|
||||
CardTemplate('Card', '$materialLib/card.dart', tokens).updateFile();
|
||||
CheckboxTemplate('Checkbox', '$materialLib/checkbox.dart', tokens).updateFile();
|
||||
DialogFullscreenTemplate('DialogFullscreen', '$materialLib/dialog.dart', tokens).updateFile();
|
||||
DialogTemplate('Dialog', '$materialLib/dialog.dart', tokens).updateFile();
|
||||
FABTemplate('FAB', '$materialLib/floating_action_button.dart', tokens).updateFile();
|
||||
FilterChipTemplate('ChoiceChip', '$materialLib/choice_chip.dart', tokens).updateFile();
|
||||
|
@ -47,3 +47,19 @@ class _${blockName}DefaultsM3 extends DialogTheme {
|
||||
}
|
||||
''';
|
||||
}
|
||||
|
||||
class DialogFullscreenTemplate extends TokenTemplate {
|
||||
const DialogFullscreenTemplate(super.blockName, super.fileName, super.tokens);
|
||||
|
||||
@override
|
||||
String generate() => '''
|
||||
class _${blockName}DefaultsM3 extends DialogTheme {
|
||||
const _${blockName}DefaultsM3(this.context);
|
||||
|
||||
final BuildContext context;
|
||||
|
||||
@override
|
||||
Color? get backgroundColor => ${componentColor("md.comp.full-screen-dialog.container")};
|
||||
}
|
||||
''';
|
||||
}
|
||||
|
86
examples/api/lib/material/dialog/dialog.0.dart
Normal file
86
examples/api/lib/material/dialog/dialog.0.dart
Normal file
@ -0,0 +1,86 @@
|
||||
// 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 [Dialog].
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
void main() => runApp(const MyApp());
|
||||
|
||||
class MyApp extends StatelessWidget {
|
||||
const MyApp({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MaterialApp(
|
||||
home: Scaffold(
|
||||
appBar: AppBar(title: const Text('Dialog Sample')),
|
||||
body: const Center(
|
||||
child: DialogExample(),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class DialogExample extends StatelessWidget {
|
||||
const DialogExample({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
TextButton(
|
||||
onPressed: () => showDialog<String>(
|
||||
context: context,
|
||||
builder: (BuildContext context) => Dialog(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
const Text('This is a typical dialog.'),
|
||||
const SizedBox(height: 15),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: const Text('Close'),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
child: const Text('Show Dialog'),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
TextButton(
|
||||
onPressed: () => showDialog<String>(
|
||||
context: context,
|
||||
builder: (BuildContext context) => Dialog.fullscreen(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
const Text('This is a fullscreen dialog.'),
|
||||
const SizedBox(height: 15),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: const Text('Close'),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
child: const Text('Show Fullscreen Dialog'),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
53
examples/api/test/material/dialog/dialog.0_test.dart
Normal file
53
examples/api/test/material/dialog/dialog.0_test.dart
Normal file
@ -0,0 +1,53 @@
|
||||
// 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/material/dialog/dialog.0.dart' as example;
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets('Show Dialog', (WidgetTester tester) async {
|
||||
const String dialogText = 'This is a typical dialog.';
|
||||
|
||||
await tester.pumpWidget(
|
||||
const MaterialApp(
|
||||
home: Scaffold(
|
||||
body: example.MyApp(),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(find.text(dialogText), findsNothing);
|
||||
|
||||
await tester.tap(find.text('Show Dialog'));
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.text(dialogText), findsOneWidget);
|
||||
|
||||
await tester.tap(find.text('Close'));
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.text(dialogText), findsNothing);
|
||||
});
|
||||
|
||||
testWidgets('Show Dialog.fullscreen', (WidgetTester tester) async {
|
||||
const String dialogText = 'This is a fullscreen dialog.';
|
||||
|
||||
await tester.pumpWidget(
|
||||
const MaterialApp(
|
||||
home: Scaffold(
|
||||
body: example.MyApp(),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(find.text(dialogText), findsNothing);
|
||||
|
||||
await tester.tap(find.text('Show Fullscreen Dialog'));
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.text(dialogText), findsOneWidget);
|
||||
|
||||
await tester.tap(find.text('Close'));
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.text(dialogText), findsNothing);
|
||||
});
|
||||
}
|
@ -31,6 +31,12 @@ const EdgeInsets _defaultInsetPadding = EdgeInsets.symmetric(horizontal: 40.0, v
|
||||
/// or [SimpleDialog], which implement specific kinds of Material Design
|
||||
/// dialogs.
|
||||
///
|
||||
/// {@tool dartpad}
|
||||
/// This sample shows the creation of [Dialog] and [Dialog.fullscreen] widgets.
|
||||
///
|
||||
/// ** See code in examples/api/lib/material/dialog/dialog.0.dart **
|
||||
/// {@end-tool}
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [AlertDialog], for dialogs that have a message and some buttons.
|
||||
@ -55,7 +61,26 @@ class Dialog extends StatelessWidget {
|
||||
this.alignment,
|
||||
this.child,
|
||||
}) : assert(clipBehavior != null),
|
||||
assert(elevation == null || elevation >= 0.0);
|
||||
assert(elevation == null || elevation >= 0.0),
|
||||
_fullscreen = false;
|
||||
|
||||
/// Creates a fullscreen dialog.
|
||||
///
|
||||
/// Typically used in conjunction with [showDialog].
|
||||
const Dialog.fullscreen({
|
||||
super.key,
|
||||
this.backgroundColor,
|
||||
this.insetAnimationDuration = Duration.zero,
|
||||
this.insetAnimationCurve = Curves.decelerate,
|
||||
this.child,
|
||||
}) : elevation = 0,
|
||||
shadowColor = null,
|
||||
surfaceTintColor = null,
|
||||
insetPadding = EdgeInsets.zero,
|
||||
clipBehavior = Clip.none,
|
||||
shape = null,
|
||||
alignment = null,
|
||||
_fullscreen = true;
|
||||
|
||||
/// {@template flutter.material.dialog.backgroundColor}
|
||||
/// The background color of the surface of this [Dialog].
|
||||
@ -130,7 +155,8 @@ class Dialog extends StatelessWidget {
|
||||
/// The duration of the animation to show when the system keyboard intrudes
|
||||
/// into the space that the dialog is placed in.
|
||||
///
|
||||
/// Defaults to 100 milliseconds.
|
||||
/// Defaults to 100 milliseconds when [Dialog] is used, and [Duration.zero]
|
||||
/// when [Dialog.fullscreen] is used.
|
||||
/// {@endtemplate}
|
||||
final Duration insetAnimationDuration;
|
||||
|
||||
@ -184,13 +210,44 @@ class Dialog extends StatelessWidget {
|
||||
/// {@macro flutter.widgets.ProxyWidget.child}
|
||||
final Widget? child;
|
||||
|
||||
/// This value is used to determine if this is a fullscreen dialog.
|
||||
final bool _fullscreen;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final ThemeData theme = Theme.of(context);
|
||||
final DialogTheme dialogTheme = DialogTheme.of(context);
|
||||
final DialogTheme defaults = theme.useMaterial3 ? _DialogDefaultsM3(context) : _DialogDefaultsM2(context);
|
||||
|
||||
final EdgeInsets effectivePadding = MediaQuery.of(context).viewInsets + (insetPadding ?? EdgeInsets.zero);
|
||||
final DialogTheme defaults = theme.useMaterial3
|
||||
? (_fullscreen ? _DialogFullscreenDefaultsM3(context) : _DialogDefaultsM3(context))
|
||||
: _DialogDefaultsM2(context);
|
||||
|
||||
Widget dialogChild;
|
||||
|
||||
if (_fullscreen) {
|
||||
dialogChild = Material(
|
||||
color: backgroundColor ?? dialogTheme.backgroundColor ?? defaults.backgroundColor,
|
||||
child: child,
|
||||
);
|
||||
} else {
|
||||
dialogChild = Align(
|
||||
alignment: alignment ?? dialogTheme.alignment ?? defaults.alignment!,
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(minWidth: 280.0),
|
||||
child: Material(
|
||||
color: backgroundColor ?? dialogTheme.backgroundColor ?? Theme.of(context).dialogBackgroundColor,
|
||||
elevation: elevation ?? dialogTheme.elevation ?? defaults.elevation!,
|
||||
shadowColor: shadowColor ?? dialogTheme.shadowColor ?? defaults.shadowColor,
|
||||
surfaceTintColor: surfaceTintColor ?? dialogTheme.surfaceTintColor ?? defaults.surfaceTintColor,
|
||||
shape: shape ?? dialogTheme.shape ?? defaults.shape!,
|
||||
type: MaterialType.card,
|
||||
clipBehavior: clipBehavior,
|
||||
child: child,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return AnimatedPadding(
|
||||
padding: effectivePadding,
|
||||
duration: insetAnimationDuration,
|
||||
@ -201,22 +258,7 @@ class Dialog extends StatelessWidget {
|
||||
removeRight: true,
|
||||
removeBottom: true,
|
||||
context: context,
|
||||
child: Align(
|
||||
alignment: alignment ?? dialogTheme.alignment ?? defaults.alignment!,
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(minWidth: 280.0),
|
||||
child: Material(
|
||||
color: backgroundColor ?? dialogTheme.backgroundColor ?? Theme.of(context).dialogBackgroundColor,
|
||||
elevation: elevation ?? dialogTheme.elevation ?? defaults.elevation!,
|
||||
shadowColor: shadowColor ?? dialogTheme.shadowColor ?? defaults.shadowColor,
|
||||
surfaceTintColor: surfaceTintColor ?? dialogTheme.surfaceTintColor ?? defaults.surfaceTintColor,
|
||||
shape: shape ?? dialogTheme.shape ?? defaults.shape!,
|
||||
type: MaterialType.card,
|
||||
clipBehavior: clipBehavior,
|
||||
child: child,
|
||||
),
|
||||
),
|
||||
),
|
||||
child: dialogChild,
|
||||
),
|
||||
);
|
||||
}
|
||||
@ -1426,3 +1468,23 @@ class _DialogDefaultsM3 extends DialogTheme {
|
||||
}
|
||||
|
||||
// END GENERATED TOKEN PROPERTIES - Dialog
|
||||
|
||||
// BEGIN GENERATED TOKEN PROPERTIES - DialogFullscreen
|
||||
|
||||
// Do not edit by hand. The code between the "BEGIN GENERATED" and
|
||||
// "END GENERATED" comments are generated from data in the Material
|
||||
// Design token database by the script:
|
||||
// dev/tools/gen_defaults/bin/gen_defaults.dart.
|
||||
|
||||
// Token database version: v0_132
|
||||
|
||||
class _DialogFullscreenDefaultsM3 extends DialogTheme {
|
||||
const _DialogFullscreenDefaultsM3(this.context);
|
||||
|
||||
final BuildContext context;
|
||||
|
||||
@override
|
||||
Color? get backgroundColor => Theme.of(context).colorScheme.surface;
|
||||
}
|
||||
|
||||
// END GENERATED TOKEN PROPERTIES - DialogFullscreen
|
||||
|
@ -6,6 +6,7 @@ import 'dart:ui';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
import '../widgets/semantics_tester.dart';
|
||||
@ -138,6 +139,53 @@ void main() {
|
||||
expect(material3Widget.elevation, 6.0);
|
||||
});
|
||||
|
||||
testWidgets('Dialog.fullscreen Defaults', (WidgetTester tester) async {
|
||||
const String dialogTextM2 = 'Fullscreen Dialog - M2';
|
||||
const String dialogTextM3 = 'Fullscreen Dialog - M3';
|
||||
|
||||
await tester.pumpWidget(_buildAppWithDialog(
|
||||
theme: material2Theme,
|
||||
const Dialog.fullscreen(
|
||||
child: Text(dialogTextM2),
|
||||
),
|
||||
));
|
||||
|
||||
await tester.tap(find.text('X'));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text(dialogTextM2), findsOneWidget);
|
||||
|
||||
Material materialWidget = _getMaterialFromDialog(tester);
|
||||
expect(materialWidget.color, Colors.grey[800]);
|
||||
|
||||
// Try to dismiss the fullscreen dialog with the escape key.
|
||||
await tester.sendKeyEvent(LogicalKeyboardKey.escape);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text(dialogTextM2), findsNothing);
|
||||
|
||||
await tester.pumpWidget(_buildAppWithDialog(
|
||||
theme: material3Theme,
|
||||
const Dialog.fullscreen(
|
||||
child: Text(dialogTextM3),
|
||||
),
|
||||
));
|
||||
|
||||
await tester.tap(find.text('X'));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text(dialogTextM3), findsOneWidget);
|
||||
|
||||
materialWidget = _getMaterialFromDialog(tester);
|
||||
expect(materialWidget.color, material3Theme.colorScheme.surface);
|
||||
|
||||
// Try to dismiss the fullscreen dialog with the escape key.
|
||||
await tester.sendKeyEvent(LogicalKeyboardKey.escape);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text(dialogTextM3), findsNothing);
|
||||
});
|
||||
|
||||
testWidgets('Custom dialog elevation', (WidgetTester tester) async {
|
||||
const double customElevation = 12.0;
|
||||
const Color shadowColor = Color(0xFF000001);
|
||||
|
Loading…
x
Reference in New Issue
Block a user