77library ;
88
99import 'package:flutter/foundation.dart' ;
10+ import 'package:flutter/gestures.dart' ;
1011import 'package:flutter/rendering.dart' ;
1112import 'package:flutter/services.dart' ;
1213import 'package:flutter/widgets.dart' ;
@@ -24,6 +25,13 @@ const double _kSqueeze = 1.45;
2425// lens.
2526const double _kOverAndUnderCenterOpacity = 0.447 ;
2627
28+ // The duration and curve of the tap-to-scroll gesture's animation when a picker
29+ // item is tapped.
30+ //
31+ // Eyeballed from an iPhone 15 Pro simulator running iOS 17.5.
32+ const Duration _kCupertinoPickerTapToScrollDuration = Duration (milliseconds: 300 );
33+ const Curve _kCupertinoPickerTapToScrollCurve = Curves .easeInOut;
34+
2735/// An iOS-styled picker.
2836///
2937/// Displays its children widgets on a wheel for selection and
@@ -258,6 +266,14 @@ class _CupertinoPickerState extends State<CupertinoPicker> {
258266 widget.onSelectedItemChanged? .call (index);
259267 }
260268
269+ void _handleChildTap (int index, FixedExtentScrollController controller) {
270+ controller.animateToItem (
271+ index,
272+ duration: _kCupertinoPickerTapToScrollDuration,
273+ curve: _kCupertinoPickerTapToScrollCurve,
274+ );
275+ }
276+
261277 /// Draws the selectionOverlay.
262278 Widget _buildSelectionOverlay (Widget selectionOverlay) {
263279 final double height = widget.itemExtent * widget.magnification;
@@ -280,15 +296,16 @@ class _CupertinoPickerState extends State<CupertinoPicker> {
280296 final Color ? resolvedBackgroundColor = CupertinoDynamicColor .maybeResolve (widget.backgroundColor, context);
281297
282298 assert (RenderListWheelViewport .defaultPerspective == _kDefaultPerspective);
299+ final FixedExtentScrollController controller = widget.scrollController ?? _controller! ;
283300 final Widget result = DefaultTextStyle (
284301 style: textStyle.copyWith (color: CupertinoDynamicColor .maybeResolve (textStyle.color, context)),
285302 child: Stack (
286303 children: < Widget > [
287304 Positioned .fill (
288305 child: _CupertinoPickerSemantics (
289- scrollController: widget.scrollController ?? _controller ! ,
306+ scrollController: controller ,
290307 child: ListWheelScrollView .useDelegate (
291- controller: widget.scrollController ?? _controller ,
308+ controller: controller ,
292309 physics: const FixedExtentScrollPhysics (),
293310 diameterRatio: widget.diameterRatio,
294311 offAxisFraction: widget.offAxisFraction,
@@ -298,7 +315,11 @@ class _CupertinoPickerState extends State<CupertinoPicker> {
298315 itemExtent: widget.itemExtent,
299316 squeeze: widget.squeeze,
300317 onSelectedItemChanged: _handleSelectedItemChanged,
301- childDelegate: widget.childDelegate,
318+ dragStartBehavior: DragStartBehavior .down,
319+ childDelegate: _CupertinoPickerListWheelChildDelegateWrapper (
320+ widget.childDelegate,
321+ onTappedChild: (int index) => _handleChildTap (index, controller),
322+ ),
302323 ),
303324 ),
304325 ),
@@ -512,3 +533,35 @@ class _RenderCupertinoPickerSemantics extends RenderProxyBox {
512533 controller.removeListener (_handleScrollUpdate);
513534 }
514535}
536+
537+ class _CupertinoPickerListWheelChildDelegateWrapper implements ListWheelChildDelegate {
538+ _CupertinoPickerListWheelChildDelegateWrapper (
539+ this ._wrapped, {
540+ required this .onTappedChild,
541+ });
542+ final ListWheelChildDelegate _wrapped;
543+ final void Function (int index) onTappedChild;
544+
545+ @override
546+ Widget ? build (BuildContext context, int index) {
547+ final Widget ? child = _wrapped.build (context, index);
548+ if (child == null ) {
549+ return child;
550+ }
551+ return GestureDetector (
552+ behavior: HitTestBehavior .translucent,
553+ excludeFromSemantics: true ,
554+ onTap: () => onTappedChild (index),
555+ child: child,
556+ );
557+ }
558+
559+ @override
560+ int ? get estimatedChildCount => _wrapped.estimatedChildCount;
561+
562+ @override
563+ bool shouldRebuild (covariant _CupertinoPickerListWheelChildDelegateWrapper oldDelegate) => _wrapped.shouldRebuild (oldDelegate._wrapped);
564+
565+ @override
566+ int trueIndexOf (int index) => _wrapped.trueIndexOf (index);
567+ }
0 commit comments