diff --git a/packages/flutter/lib/src/cupertino/date_picker.dart b/packages/flutter/lib/src/cupertino/date_picker.dart index 9a8768e58c..1b43e697bc 100644 --- a/packages/flutter/lib/src/cupertino/date_picker.dart +++ b/packages/flutter/lib/src/cupertino/date_picker.dart @@ -290,8 +290,13 @@ class CupertinoDatePicker extends StatefulWidget { this.use24hFormat = false, this.dateOrder, this.backgroundColor, - this.showDayOfWeek = false + this.showDayOfWeek = false, + this.itemExtent = _kItemExtent, }) : initialDateTime = initialDateTime ?? DateTime.now(), + assert( + itemExtent > 0, + 'item extent should be greater than 0', + ), assert( minuteInterval > 0 && 60 % minuteInterval == 0, 'minute interval is not a positive integer factor of 60', @@ -406,6 +411,11 @@ class CupertinoDatePicker extends StatefulWidget { /// Whether to to show day of week alongside day. Defaults to false. final bool showDayOfWeek; + /// {@macro flutter.cupertino.picker.itemExtent} + /// + /// Defaults to a value that matches the default iOS date picker wheel. + final double itemExtent; + @override State createState() { // ignore: no_logic_in_create_state, https://github.com/flutter/flutter/issues/70499 // The `time` mode and `dateAndTime` mode of the picker share the time @@ -725,7 +735,7 @@ class _CupertinoDatePickerDateTimeState extends State { child: CupertinoPicker.builder( scrollController: dateController, offAxisFraction: offAxisFraction, - itemExtent: _kItemExtent, + itemExtent: widget.itemExtent, useMagnifier: _kUseMagnifier, magnification: _kMagnification, backgroundColor: widget.backgroundColor, @@ -803,7 +813,7 @@ class _CupertinoDatePickerDateTimeState extends State { child: CupertinoPicker( scrollController: hourController, offAxisFraction: offAxisFraction, - itemExtent: _kItemExtent, + itemExtent: widget.itemExtent, useMagnifier: _kUseMagnifier, magnification: _kMagnification, backgroundColor: widget.backgroundColor, @@ -868,7 +878,7 @@ class _CupertinoDatePickerDateTimeState extends State { child: CupertinoPicker( scrollController: minuteController, offAxisFraction: offAxisFraction, - itemExtent: _kItemExtent, + itemExtent: widget.itemExtent, useMagnifier: _kUseMagnifier, magnification: _kMagnification, backgroundColor: widget.backgroundColor, @@ -918,7 +928,7 @@ class _CupertinoDatePickerDateTimeState extends State { child: CupertinoPicker( scrollController: meridiemController, offAxisFraction: offAxisFraction, - itemExtent: _kItemExtent, + itemExtent: widget.itemExtent, useMagnifier: _kUseMagnifier, magnification: _kMagnification, backgroundColor: widget.backgroundColor, @@ -1211,7 +1221,7 @@ class _CupertinoDatePickerDateState extends State { child: CupertinoPicker( scrollController: dayController, offAxisFraction: offAxisFraction, - itemExtent: _kItemExtent, + itemExtent: widget.itemExtent, useMagnifier: _kUseMagnifier, magnification: _kMagnification, backgroundColor: widget.backgroundColor, @@ -1254,7 +1264,7 @@ class _CupertinoDatePickerDateState extends State { child: CupertinoPicker( scrollController: monthController, offAxisFraction: offAxisFraction, - itemExtent: _kItemExtent, + itemExtent: widget.itemExtent, useMagnifier: _kUseMagnifier, magnification: _kMagnification, backgroundColor: widget.backgroundColor, @@ -1298,7 +1308,7 @@ class _CupertinoDatePickerDateState extends State { }, child: CupertinoPicker.builder( scrollController: yearController, - itemExtent: _kItemExtent, + itemExtent: widget.itemExtent, offAxisFraction: offAxisFraction, useMagnifier: _kUseMagnifier, magnification: _kMagnification, @@ -1895,13 +1905,18 @@ class CupertinoTimerPicker extends StatefulWidget { this.secondInterval = 1, this.alignment = Alignment.center, this.backgroundColor, + this.itemExtent = _kItemExtent, required this.onTimerDurationChanged, }) : assert(initialTimerDuration >= Duration.zero), assert(initialTimerDuration < const Duration(days: 1)), assert(minuteInterval > 0 && 60 % minuteInterval == 0), assert(secondInterval > 0 && 60 % secondInterval == 0), assert(initialTimerDuration.inMinutes % minuteInterval == 0), - assert(initialTimerDuration.inSeconds % secondInterval == 0); + assert(initialTimerDuration.inSeconds % secondInterval == 0), + assert( + itemExtent > 0, + 'item extent should be greater than 0' + ); /// The mode of the timer picker. final CupertinoTimerPickerMode mode; @@ -1930,6 +1945,11 @@ class CupertinoTimerPicker extends StatefulWidget { /// Defaults to null, which disables background painting entirely. final Color? backgroundColor; + /// {@macro flutter.cupertino.picker.itemExtent} + /// + /// Defaults to a value that matches the default iOS timer picker wheel. + final double itemExtent; + @override State createState() => _CupertinoTimerPickerState(); } @@ -2148,7 +2168,7 @@ class _CupertinoTimerPickerState extends State { scrollController: FixedExtentScrollController(initialItem: selectedHour!), magnification: _kMagnification, offAxisFraction: _calculateOffAxisFraction(additionalPadding.start, 0), - itemExtent: _kItemExtent, + itemExtent: widget.itemExtent, backgroundColor: widget.backgroundColor, squeeze: _kSqueeze, onSelectedItemChanged: (int index) { @@ -2212,7 +2232,7 @@ class _CupertinoTimerPickerState extends State { additionalPadding.start, widget.mode == CupertinoTimerPickerMode.ms ? 0 : 1, ), - itemExtent: _kItemExtent, + itemExtent: widget.itemExtent, backgroundColor: widget.backgroundColor, squeeze: _kSqueeze, looping: true, @@ -2278,7 +2298,7 @@ class _CupertinoTimerPickerState extends State { additionalPadding.start, widget.mode == CupertinoTimerPickerMode.ms ? 1 : 2, ), - itemExtent: _kItemExtent, + itemExtent: widget.itemExtent, backgroundColor: widget.backgroundColor, squeeze: _kSqueeze, looping: true, diff --git a/packages/flutter/lib/src/cupertino/picker.dart b/packages/flutter/lib/src/cupertino/picker.dart index 0769b88668..11f032b449 100644 --- a/packages/flutter/lib/src/cupertino/picker.dart +++ b/packages/flutter/lib/src/cupertino/picker.dart @@ -162,10 +162,12 @@ class CupertinoPicker extends StatefulWidget { /// If null, an implicit one will be created internally. final FixedExtentScrollController? scrollController; + /// {@template flutter.cupertino.picker.itemExtent} /// The uniform height of all children. /// /// All children will be given the [BoxConstraints] to match this exact - /// height. Must not be null and must be positive. + /// height. Must be a positive value. + /// {@endtemplate} final double itemExtent; /// {@macro flutter.rendering.RenderListWheelViewport.squeeze} diff --git a/packages/flutter/test/cupertino/date_picker_test.dart b/packages/flutter/test/cupertino/date_picker_test.dart index 9a44a7c32c..3935d30ea7 100644 --- a/packages/flutter/test/cupertino/date_picker_test.dart +++ b/packages/flutter/test/cupertino/date_picker_test.dart @@ -148,6 +148,20 @@ void main() { expect(pickers.any((CupertinoPicker picker) => picker.backgroundColor != CupertinoColors.black), false); }); + testWidgets('specified item extent value is applied', (WidgetTester tester) async { + await tester.pumpWidget( + CupertinoApp( + home: CupertinoTimerPicker( + itemExtent: 42, + onTimerDurationChanged: (_) { }, + ), + ), + ); + + final Iterable pickers = tester.allWidgets.whereType(); + expect(pickers.any((CupertinoPicker picker) => picker.itemExtent != 42), false); + }); + testWidgets('columns are ordered correctly when text direction is ltr', (WidgetTester tester) async { await tester.pumpWidget( CupertinoApp( @@ -320,6 +334,20 @@ void main() { expect(pickers.any((CupertinoPicker picker) => picker.backgroundColor != CupertinoColors.black), false); }); + testWidgets('specified item extent value is applied', (WidgetTester tester) async { + await tester.pumpWidget( + CupertinoApp( + home: CupertinoDatePicker( + itemExtent: 55, + onDateTimeChanged: (_) { }, + ), + ), + ); + + final Iterable pickers = tester.allWidgets.whereType(); + expect(pickers.any((CupertinoPicker picker) => picker.itemExtent != 55), false); + }); + testWidgets('initial date honors minuteInterval', (WidgetTester tester) async { late DateTime newDateTime; await tester.pumpWidget(