Add builder parameter to showDatePicker, showTimePicker (#27703)
This commit is contained in:
parent
1e5d2e55fc
commit
5ee5766c89
@ -25,6 +25,9 @@ import 'material_localizations.dart';
|
|||||||
import 'text_theme.dart';
|
import 'text_theme.dart';
|
||||||
import 'theme.dart';
|
import 'theme.dart';
|
||||||
|
|
||||||
|
// Examples can assume:
|
||||||
|
// BuildContext context;
|
||||||
|
|
||||||
/// Initial display mode of the date picker dialog.
|
/// Initial display mode of the date picker dialog.
|
||||||
///
|
///
|
||||||
/// Date picker UI mode for either showing a list of available years or a
|
/// Date picker UI mode for either showing a list of available years or a
|
||||||
@ -1111,6 +1114,28 @@ typedef SelectableDayPredicate = bool Function(DateTime day);
|
|||||||
/// The [context] argument is passed to [showDialog], the documentation for
|
/// The [context] argument is passed to [showDialog], the documentation for
|
||||||
/// which discusses how it is used.
|
/// which discusses how it is used.
|
||||||
///
|
///
|
||||||
|
/// The [builder] parameter can be used to wrap the dialog widget
|
||||||
|
/// to add inherited widgets like [Theme].
|
||||||
|
///
|
||||||
|
/// {@tool sample}
|
||||||
|
/// Show a date picker with the dark theme.
|
||||||
|
///
|
||||||
|
/// ```dart
|
||||||
|
/// Future<DateTime> selectedDate = showDatePicker(
|
||||||
|
/// context: context,
|
||||||
|
/// initialDate: DateTime.now(),
|
||||||
|
/// firstDate: DateTime(2018),
|
||||||
|
/// lastDate: DateTime(2030),
|
||||||
|
/// builder: (BuildContext context, Widget child) {
|
||||||
|
/// return Theme(
|
||||||
|
/// data: ThemeData.dark(),
|
||||||
|
/// child: child,
|
||||||
|
/// );
|
||||||
|
/// },
|
||||||
|
/// );
|
||||||
|
/// ```
|
||||||
|
/// {@end-tool}
|
||||||
|
///
|
||||||
/// The [context], [initialDate], [firstDate], and [lastDate] parameters must
|
/// The [context], [initialDate], [firstDate], and [lastDate] parameters must
|
||||||
/// not be null.
|
/// not be null.
|
||||||
///
|
///
|
||||||
@ -1133,6 +1158,7 @@ Future<DateTime> showDatePicker({
|
|||||||
DatePickerMode initialDatePickerMode = DatePickerMode.day,
|
DatePickerMode initialDatePickerMode = DatePickerMode.day,
|
||||||
Locale locale,
|
Locale locale,
|
||||||
TextDirection textDirection,
|
TextDirection textDirection,
|
||||||
|
TransitionBuilder builder,
|
||||||
}) async {
|
}) async {
|
||||||
assert(initialDate != null);
|
assert(initialDate != null);
|
||||||
assert(firstDate != null);
|
assert(firstDate != null);
|
||||||
@ -1173,6 +1199,8 @@ Future<DateTime> showDatePicker({
|
|||||||
|
|
||||||
return await showDialog<DateTime>(
|
return await showDialog<DateTime>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext context) => child,
|
builder: (BuildContext context) {
|
||||||
|
return builder == null ? child : builder(context, child);
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,9 @@ import 'theme.dart';
|
|||||||
import 'theme_data.dart';
|
import 'theme_data.dart';
|
||||||
import 'time.dart';
|
import 'time.dart';
|
||||||
|
|
||||||
|
// Examples can assume:
|
||||||
|
// BuildContext context;
|
||||||
|
|
||||||
const Duration _kDialAnimateDuration = Duration(milliseconds: 200);
|
const Duration _kDialAnimateDuration = Duration(milliseconds: 200);
|
||||||
const double _kTwoPi = 2 * math.pi;
|
const double _kTwoPi = 2 * math.pi;
|
||||||
const Duration _kVibrateCommitDelay = Duration(milliseconds: 100);
|
const Duration _kVibrateCommitDelay = Duration(milliseconds: 100);
|
||||||
@ -1651,33 +1654,77 @@ class _TimePickerDialogState extends State<_TimePickerDialog> {
|
|||||||
/// The returned Future resolves to the time selected by the user when the user
|
/// The returned Future resolves to the time selected by the user when the user
|
||||||
/// closes the dialog. If the user cancels the dialog, null is returned.
|
/// closes the dialog. If the user cancels the dialog, null is returned.
|
||||||
///
|
///
|
||||||
/// To show a dialog with [initialTime] equal to the current time:
|
/// {@tool sample}
|
||||||
|
/// Show a dialog with [initialTime] equal to the current time.
|
||||||
///
|
///
|
||||||
/// ```dart
|
/// ```dart
|
||||||
/// showTimePicker(
|
/// Future<TimeOfDay> selectedTime = showTimePicker(
|
||||||
/// initialTime: TimeOfDay.now(),
|
/// initialTime: TimeOfDay.now(),
|
||||||
/// context: context,
|
/// context: context,
|
||||||
/// );
|
/// );
|
||||||
/// ```
|
/// ```
|
||||||
|
/// {@end-tool}
|
||||||
///
|
///
|
||||||
/// The `context` argument is passed to [showDialog], the documentation for
|
/// The [context] argument is passed to [showDialog], the documentation for
|
||||||
/// which discusses how it is used.
|
/// which discusses how it is used.
|
||||||
///
|
///
|
||||||
|
/// The [builder] parameter can be used to wrap the dialog widget
|
||||||
|
/// to add inherited widgets like [Localizations.override],
|
||||||
|
/// [Directionality], or [MediaQuery].
|
||||||
|
///
|
||||||
|
/// {@tool sample}
|
||||||
|
/// Show a dialog with the text direction overridden to be [TextDirection.rtl].
|
||||||
|
///
|
||||||
|
/// ```dart
|
||||||
|
/// Future<TimeOfDay> selectedTimeRTL = showTimePicker(
|
||||||
|
/// context: context,
|
||||||
|
/// initialTime: TimeOfDay.now(),
|
||||||
|
/// builder: (BuildContext context, Widget child) {
|
||||||
|
/// return Directionality(
|
||||||
|
/// textDirection: TextDirection.rtl,
|
||||||
|
/// child: child,
|
||||||
|
/// );
|
||||||
|
/// },
|
||||||
|
/// );
|
||||||
|
/// ```
|
||||||
|
/// {@end-tool}
|
||||||
|
///
|
||||||
|
/// {@tool sample}
|
||||||
|
/// Show a dialog with time unconditionally displayed in 24 hour format.
|
||||||
|
///
|
||||||
|
/// ```dart
|
||||||
|
/// Future<TimeOfDay> selectedTime24Hour = showTimePicker(
|
||||||
|
/// context: context,
|
||||||
|
/// initialTime: TimeOfDay(hour: 10, minute: 47),
|
||||||
|
/// builder: (BuildContext context, Widget child) {
|
||||||
|
/// return MediaQuery(
|
||||||
|
/// data: MediaQuery.of(context).copyWith(alwaysUse24HourFormat: true),
|
||||||
|
/// child: child,
|
||||||
|
/// );
|
||||||
|
/// },
|
||||||
|
/// );
|
||||||
|
/// ```
|
||||||
|
/// {@end-tool}
|
||||||
|
///
|
||||||
/// See also:
|
/// See also:
|
||||||
///
|
///
|
||||||
/// * [showDatePicker], which shows a dialog that contains a material design
|
/// * [showDatePicker], which shows a dialog that contains a material design
|
||||||
/// date picker.
|
/// date picker.
|
||||||
Future<TimeOfDay> showTimePicker({
|
Future<TimeOfDay> showTimePicker({
|
||||||
@required BuildContext context,
|
@required BuildContext context,
|
||||||
@required TimeOfDay initialTime
|
@required TimeOfDay initialTime,
|
||||||
|
TransitionBuilder builder,
|
||||||
}) async {
|
}) async {
|
||||||
assert(context != null);
|
assert(context != null);
|
||||||
assert(initialTime != null);
|
assert(initialTime != null);
|
||||||
assert(debugCheckHasMaterialLocalizations(context));
|
assert(debugCheckHasMaterialLocalizations(context));
|
||||||
|
|
||||||
|
final Widget dialog = _TimePickerDialog(initialTime: initialTime);
|
||||||
return await showDialog<TimeOfDay>(
|
return await showDialog<TimeOfDay>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext context) => _TimePickerDialog(initialTime: initialTime),
|
builder: (BuildContext context) {
|
||||||
|
return builder == null ? dialog : builder(context, dialog);
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -723,4 +723,54 @@ void _tests() {
|
|||||||
expect(renderer.opacity.status, equals(AnimationStatus.dismissed));
|
expect(renderer.opacity.status, equals(AnimationStatus.dismissed));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWidgets('builder parameter', (WidgetTester tester) async {
|
||||||
|
Widget buildFrame(TextDirection textDirection) {
|
||||||
|
return MaterialApp(
|
||||||
|
home: Material(
|
||||||
|
child: Center(
|
||||||
|
child: Builder(
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return RaisedButton(
|
||||||
|
child: const Text('X'),
|
||||||
|
onPressed: () {
|
||||||
|
showDatePicker(
|
||||||
|
context: context,
|
||||||
|
initialDate: DateTime.now(),
|
||||||
|
firstDate: DateTime(2018),
|
||||||
|
lastDate: DateTime(2030),
|
||||||
|
builder: (BuildContext context, Widget child) {
|
||||||
|
return Directionality(
|
||||||
|
textDirection: textDirection,
|
||||||
|
child: child,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
await tester.pumpWidget(buildFrame(TextDirection.ltr));
|
||||||
|
await tester.tap(find.text('X'));
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
final double ltrOkRight = tester.getBottomRight(find.text('OK')).dx;
|
||||||
|
|
||||||
|
await tester.tap(find.text('OK')); // dismiss the dialog
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
await tester.pumpWidget(buildFrame(TextDirection.rtl));
|
||||||
|
await tester.tap(find.text('X'));
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
// Verify that the time picker is being laid out RTL.
|
||||||
|
// We expect the left edge of the 'OK' button in the RTL
|
||||||
|
// layout to match the gap between right edge of the 'OK'
|
||||||
|
// button and the right edge of the 800 wide window.
|
||||||
|
expect(tester.getBottomLeft(find.text('OK')).dx, 800 - ltrOkRight);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
@ -505,6 +505,54 @@ void _tests() {
|
|||||||
|
|
||||||
semantics.dispose();
|
semantics.dispose();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWidgets('builder parameter', (WidgetTester tester) async {
|
||||||
|
Widget buildFrame(TextDirection textDirection) {
|
||||||
|
return MaterialApp(
|
||||||
|
home: Material(
|
||||||
|
child: Center(
|
||||||
|
child: Builder(
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return RaisedButton(
|
||||||
|
child: const Text('X'),
|
||||||
|
onPressed: () {
|
||||||
|
showTimePicker(
|
||||||
|
context: context,
|
||||||
|
initialTime: const TimeOfDay(hour: 7, minute: 0),
|
||||||
|
builder: (BuildContext context, Widget child) {
|
||||||
|
return Directionality(
|
||||||
|
textDirection: textDirection,
|
||||||
|
child: child,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
await tester.pumpWidget(buildFrame(TextDirection.ltr));
|
||||||
|
await tester.tap(find.text('X'));
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
final double ltrOkRight = tester.getBottomRight(find.text('OK')).dx;
|
||||||
|
|
||||||
|
await tester.tap(find.text('OK')); // dismiss the dialog
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
await tester.pumpWidget(buildFrame(TextDirection.rtl));
|
||||||
|
await tester.tap(find.text('X'));
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
// Verify that the time picker is being laid out RTL.
|
||||||
|
// We expect the left edge of the 'OK' button in the RTL
|
||||||
|
// layout to match the gap between right edge of the 'OK'
|
||||||
|
// button and the right edge of the 800 wide window.
|
||||||
|
expect(tester.getBottomLeft(find.text('OK')).dx, 800 - ltrOkRight);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
final Finder findDialPaint = find.descendant(
|
final Finder findDialPaint = find.descendant(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user