diff --git a/packages/flutter/lib/src/cupertino/date_picker.dart b/packages/flutter/lib/src/cupertino/date_picker.dart index 71d3c8f96b..37bdbe96ac 100644 --- a/packages/flutter/lib/src/cupertino/date_picker.dart +++ b/packages/flutter/lib/src/cupertino/date_picker.dart @@ -24,8 +24,6 @@ const double _kDatePickerPadSize = 12.0; // The density of a date picker is different from a generic picker. // Eyeballed from iOS. const double _kSqueeze = 1.25; -// Considers setting the default background color from the theme, in the future. -const Color _kBackgroundColor = CupertinoColors.white; const TextStyle _kDefaultPickerTextStyle = TextStyle( letterSpacing: -0.83, @@ -230,12 +228,11 @@ class CupertinoDatePicker extends StatefulWidget { this.maximumYear, this.minuteInterval = 1, this.use24hFormat = false, - this.backgroundColor = _kBackgroundColor, + this.backgroundColor, }) : initialDateTime = initialDateTime ?? DateTime.now(), assert(mode != null), assert(onDateTimeChanged != null), assert(minimumYear != null), - assert(backgroundColor != null), assert( minuteInterval > 0 && 60 % minuteInterval == 0, 'minute interval is not a positive integer factor of 60', @@ -313,7 +310,7 @@ class CupertinoDatePicker extends StatefulWidget { /// Background color of date picker. /// - /// Defaults to [CupertinoColors.white] when null. + /// Defaults to null, which disables background painting entirely. final Color backgroundColor; @override @@ -1242,7 +1239,7 @@ class CupertinoTimerPicker extends StatefulWidget { this.minuteInterval = 1, this.secondInterval = 1, this.alignment = Alignment.center, - this.backgroundColor = _kBackgroundColor, + this.backgroundColor, @required this.onTimerDurationChanged, }) : assert(mode != null), assert(onTimerDurationChanged != null), @@ -1252,7 +1249,6 @@ class CupertinoTimerPicker extends StatefulWidget { assert(secondInterval > 0 && 60 % secondInterval == 0), assert(initialTimerDuration.inMinutes % minuteInterval == 0), assert(initialTimerDuration.inSeconds % secondInterval == 0), - assert(backgroundColor != null), assert(alignment != null), super(key: key); @@ -1280,7 +1276,7 @@ class CupertinoTimerPicker extends StatefulWidget { /// Background color of timer picker. /// - /// Defaults to [CupertinoColors.white] when null. + /// Defaults to null, which disables background painting entirely. final Color backgroundColor; @override @@ -1687,7 +1683,7 @@ class _CupertinoTimerPickerState extends State { child: Align( alignment: widget.alignment, child: Container( - color: _kBackgroundColor, + color: CupertinoDynamicColor.resolve(widget.backgroundColor, context), width: totalWidth, height: _kPickerHeight, child: DefaultTextStyle( diff --git a/packages/flutter/lib/src/cupertino/picker.dart b/packages/flutter/lib/src/cupertino/picker.dart index 26b220a4ca..f20f796f0d 100644 --- a/packages/flutter/lib/src/cupertino/picker.dart +++ b/packages/flutter/lib/src/cupertino/picker.dart @@ -7,19 +7,23 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; +import 'colors.dart'; import 'theme.dart'; /// Color of the 'magnifier' lens border. -const Color _kHighlighterBorder = Color(0xFF7F7F7F); -const Color _kDefaultBackground = Color(0xFFD2D4DB); +const Color _kHighlighterBorder = CupertinoDynamicColor.withBrightness( + color: Color(0x33000000), + darkColor: Color(0x33FFFFFF), +); // Eyeballed values comparing with a native picker to produce the right // curvatures and densities. const double _kDefaultDiameterRatio = 1.07; const double _kDefaultPerspective = 0.003; const double _kSqueeze = 1.45; -/// Opacity fraction value that hides the wheel above and below the 'magnifier' -/// lens with the same color as the background. -const double _kForegroundScreenOpacityFraction = 0.7; + +// Opacity fraction value that dims the wheel above and below the "magnifier" +// lens. +const double _kOverAndUnderCenterOpacity = 0.447; /// An iOS-styled picker. /// @@ -65,7 +69,7 @@ class CupertinoPicker extends StatefulWidget { CupertinoPicker({ Key key, this.diameterRatio = _kDefaultDiameterRatio, - this.backgroundColor = _kDefaultBackground, + this.backgroundColor, this.offAxisFraction = 0.0, this.useMagnifier = false, this.magnification = 1.0, @@ -108,7 +112,7 @@ class CupertinoPicker extends StatefulWidget { CupertinoPicker.builder({ Key key, this.diameterRatio = _kDefaultDiameterRatio, - this.backgroundColor = _kDefaultBackground, + this.backgroundColor, this.offAxisFraction = 0.0, this.useMagnifier = false, this.magnification = 1.0, @@ -245,110 +249,32 @@ class _CupertinoPickerState extends State { } } - /// Makes the fade to [CupertinoPicker.backgroundColor] edge gradients. - Widget _buildGradientScreen() { - // Because BlendMode.dstOut doesn't work correctly with BoxDecoration we - // have to just do a color blend. And a due to the way we are layering - // the magnifier and the gradient on the background, using a transparent - // background color makes the picker look odd. - if (widget.backgroundColor != null && widget.backgroundColor.alpha < 255) - return Container(); - - final Color widgetBackgroundColor = widget.backgroundColor ?? const Color(0xFFFFFFFF); - return Positioned.fill( - child: IgnorePointer( - child: Container( - decoration: BoxDecoration( - gradient: LinearGradient( - colors: [ - widgetBackgroundColor, - widgetBackgroundColor.withAlpha(0xF2), - widgetBackgroundColor.withAlpha(0xDD), - widgetBackgroundColor.withAlpha(0), - widgetBackgroundColor.withAlpha(0), - widgetBackgroundColor.withAlpha(0xDD), - widgetBackgroundColor.withAlpha(0xF2), - widgetBackgroundColor, - ], - stops: const [ - 0.0, 0.05, 0.09, 0.22, 0.78, 0.91, 0.95, 1.0, - ], - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - ), - ), - ), - ), - ); - } - - /// Makes the magnifier lens look so that the colors are normal through - /// the lens and partially grayed out around it. + /// Draws the magnifier borders. Widget _buildMagnifierScreen() { - final Color foreground = widget.backgroundColor?.withAlpha( - (widget.backgroundColor.alpha * _kForegroundScreenOpacityFraction).toInt() - ); + final Color resolvedBorderColor = CupertinoDynamicColor.resolve(_kHighlighterBorder, context); return IgnorePointer( - child: Column( - children: [ - Expanded( - child: Container( - color: foreground, + child: Center( + child: Container( + decoration: BoxDecoration( + border: Border( + top: BorderSide(width: 0.0, color: resolvedBorderColor), + bottom: BorderSide(width: 0.0, color: resolvedBorderColor), ), ), - Container( - decoration: const BoxDecoration( - border: Border( - top: BorderSide(width: 0.0, color: _kHighlighterBorder), - bottom: BorderSide(width: 0.0, color: _kHighlighterBorder), - ), - ), - constraints: BoxConstraints.expand( - height: widget.itemExtent * widget.magnification, - ), - ), - Expanded( - child: Container( - color: foreground, - ), - ), - ], - ), - ); - } - - Widget _buildUnderMagnifierScreen() { - final Color foreground = widget.backgroundColor?.withAlpha( - (widget.backgroundColor.alpha * _kForegroundScreenOpacityFraction).toInt() - ); - - return Column( - children: [ - Expanded(child: Container()), - Container( - color: foreground, constraints: BoxConstraints.expand( height: widget.itemExtent * widget.magnification, ), ), - Expanded(child: Container()), - ], - ); - } - - Widget _addBackgroundToChild(Widget child) { - return DecoratedBox( - decoration: BoxDecoration( - color: widget.backgroundColor, ), - child: child, ); } @override Widget build(BuildContext context) { - Widget result = DefaultTextStyle( + final Color resolvedBackgroundColor = CupertinoDynamicColor.resolve(widget.backgroundColor, context); + + final Widget result = DefaultTextStyle( style: CupertinoTheme.of(context).textTheme.pickerTextStyle, child: Stack( children: [ @@ -363,6 +289,7 @@ class _CupertinoPickerState extends State { offAxisFraction: widget.offAxisFraction, useMagnifier: widget.useMagnifier, magnification: widget.magnification, + overAndUnderCenterOpacity: _kOverAndUnderCenterOpacity, itemExtent: widget.itemExtent, squeeze: widget.squeeze, onSelectedItemChanged: _handleSelectedItemChanged, @@ -370,24 +297,15 @@ class _CupertinoPickerState extends State { ), ), ), - _buildGradientScreen(), _buildMagnifierScreen(), ], ), ); - // Adds the appropriate opacity under the magnifier if the background - // color is transparent. - if (widget.backgroundColor != null && widget.backgroundColor.alpha < 255) { - result = Stack( - children: [ - _buildUnderMagnifierScreen(), - _addBackgroundToChild(result), - ], - ); - } else { - result = _addBackgroundToChild(result); - } - return result; + + return DecoratedBox( + decoration: BoxDecoration(color: resolvedBackgroundColor), + child: result, + ); } } diff --git a/packages/flutter/lib/src/rendering/list_wheel_viewport.dart b/packages/flutter/lib/src/rendering/list_wheel_viewport.dart index ade2483e76..7ae0aabf97 100644 --- a/packages/flutter/lib/src/rendering/list_wheel_viewport.dart +++ b/packages/flutter/lib/src/rendering/list_wheel_viewport.dart @@ -140,6 +140,7 @@ class RenderListWheelViewport double offAxisFraction = 0, bool useMagnifier = false, double magnification = 1, + double overAndUnderCenterOpacity = 1, @required double itemExtent, double squeeze = 1, bool clipToSize = true, @@ -156,6 +157,8 @@ class RenderListWheelViewport assert(useMagnifier != null), assert(magnification != null), assert(magnification > 0), + assert(overAndUnderCenterOpacity != null), + assert(overAndUnderCenterOpacity >= 0 && overAndUnderCenterOpacity <= 1), assert(itemExtent != null), assert(squeeze != null), assert(squeeze > 0), @@ -172,6 +175,7 @@ class RenderListWheelViewport _offAxisFraction = offAxisFraction, _useMagnifier = useMagnifier, _magnification = magnification, + _overAndUnderCenterOpacity = overAndUnderCenterOpacity, _itemExtent = itemExtent, _squeeze = squeeze, _clipToSize = clipToSize, @@ -368,6 +372,25 @@ class RenderListWheelViewport markNeedsPaint(); } + /// {@template flutter.rendering.wheelList.overAndUnderCenterOpacity} + /// The opacity value that will be applied to the wheel that appears below and + /// above the magnifier. + /// + /// The default value is 1.0, which will not change anything. + /// + /// Must be greater than or equal to 0, and less than or equal to 1. + /// {@endtemplate} + double get overAndUnderCenterOpacity => _overAndUnderCenterOpacity; + double _overAndUnderCenterOpacity = 1.0; + set overAndUnderCenterOpacity(double value) { + assert(value != null); + assert(value >= 0 && value <= 1); + if (value == _overAndUnderCenterOpacity) + return; + _overAndUnderCenterOpacity = value; + markNeedsPaint(); + } + /// {@template flutter.rendering.wheelList.itemExtent} /// The size of the children along the main axis. Children [RenderBox]es will /// be given the [BoxConstraints] of this exact size. @@ -822,20 +845,16 @@ class RenderListWheelViewport // Offset that helps painting everything in the center (e.g. angle = 0). final Offset offsetToCenter = Offset( - untransformedPaintingCoordinates.dx, - -_topScrollMarginExtent); + untransformedPaintingCoordinates.dx, + -_topScrollMarginExtent, + ); - if (!useMagnifier) + final bool shouldApplyOffCenterDim = overAndUnderCenterOpacity < 1; + if (useMagnifier || shouldApplyOffCenterDim) { + _paintChildWithMagnifier(context, offset, child, transform, offsetToCenter, untransformedPaintingCoordinates); + } else { _paintChildCylindrically(context, offset, child, transform, offsetToCenter); - else - _paintChildWithMagnifier( - context, - offset, - child, - transform, - offsetToCenter, - untransformedPaintingCoordinates, - ); + } } /// Paint child with the magnifier active - the child will be rendered @@ -878,36 +897,34 @@ class RenderListWheelViewport // Clipping the part in the center. context.pushClipRect( - false, - offset, - centerRect, - (PaintingContext context, Offset offset) { - context.pushTransform( - false, - offset, - _magnifyTransform(), - (PaintingContext context, Offset offset) { - context.paintChild( - child, - offset + untransformedPaintingCoordinates); - }); + needsCompositing, + offset, + centerRect, + (PaintingContext context, Offset offset) { + context.pushTransform( + needsCompositing, + offset, + _magnifyTransform(), + (PaintingContext context, Offset offset) { + context.paintChild(child, offset + untransformedPaintingCoordinates); }); + }); // Clipping the part in either the top-half or bottom-half of the wheel. context.pushClipRect( - false, - offset, - untransformedPaintingCoordinates.dy <= magnifierTopLinePosition - ? topHalfRect - : bottomHalfRect, - (PaintingContext context, Offset offset) { - _paintChildCylindrically( - context, - offset, - child, - cylindricalTransform, - offsetToCenter); - }, + needsCompositing, + offset, + untransformedPaintingCoordinates.dy <= magnifierTopLinePosition + ? topHalfRect + : bottomHalfRect, + (PaintingContext context, Offset offset) { + _paintChildCylindrically( + context, + offset, + child, + cylindricalTransform, + offsetToCenter); + }, ); } else { _paintChildCylindrically( @@ -927,20 +944,26 @@ class RenderListWheelViewport Matrix4 cylindricalTransform, Offset offsetToCenter, ) { + // Paint child cylindrically, without [overAndUnderCenterOpacity]. + final PaintingContextCallback painter = (PaintingContext context, Offset offset) { + context.paintChild( + child, + // Paint everything in the center (e.g. angle = 0), then transform. + offset + offsetToCenter, + ); + }; + + // Paint child cylindrically, with [overAndUnderCenterOpacity]. + final PaintingContextCallback opacityPainter = (PaintingContext context, Offset offset) { + context.pushOpacity(offset, (overAndUnderCenterOpacity * 255).round(), painter); + }; + context.pushTransform( - // Text with TransformLayers and no cullRects currently have an issue rendering - // https://github.com/flutter/flutter/issues/14224. - false, + needsCompositing, offset, _centerOriginTransform(cylindricalTransform), // Pre-transform painting function. - (PaintingContext context, Offset offset) { - context.paintChild( - child, - // Paint everything in the center (e.g. angle = 0), then transform. - offset + offsetToCenter, - ); - }, + overAndUnderCenterOpacity == 1 ? painter : opacityPainter, ); } diff --git a/packages/flutter/lib/src/widgets/list_wheel_scroll_view.dart b/packages/flutter/lib/src/widgets/list_wheel_scroll_view.dart index 96673923f4..b88d1962a2 100644 --- a/packages/flutter/lib/src/widgets/list_wheel_scroll_view.dart +++ b/packages/flutter/lib/src/widgets/list_wheel_scroll_view.dart @@ -575,6 +575,7 @@ class ListWheelScrollView extends StatefulWidget { this.offAxisFraction = 0.0, this.useMagnifier = false, this.magnification = 1.0, + this.overAndUnderCenterOpacity = 1.0, @required this.itemExtent, this.squeeze = 1.0, this.onSelectedItemChanged, @@ -588,6 +589,8 @@ class ListWheelScrollView extends StatefulWidget { assert(perspective > 0), assert(perspective <= 0.01, RenderListWheelViewport.perspectiveTooHighMessage), assert(magnification > 0), + assert(overAndUnderCenterOpacity != null), + assert(overAndUnderCenterOpacity >= 0 && overAndUnderCenterOpacity <= 1), assert(itemExtent != null), assert(itemExtent > 0), assert(squeeze != null), @@ -612,6 +615,7 @@ class ListWheelScrollView extends StatefulWidget { this.offAxisFraction = 0.0, this.useMagnifier = false, this.magnification = 1.0, + this.overAndUnderCenterOpacity = 1.0, @required this.itemExtent, this.squeeze = 1.0, this.onSelectedItemChanged, @@ -625,6 +629,8 @@ class ListWheelScrollView extends StatefulWidget { assert(perspective > 0), assert(perspective <= 0.01, RenderListWheelViewport.perspectiveTooHighMessage), assert(magnification > 0), + assert(overAndUnderCenterOpacity != null), + assert(overAndUnderCenterOpacity >= 0 && overAndUnderCenterOpacity <= 1), assert(itemExtent != null), assert(itemExtent > 0), assert(squeeze != null), @@ -677,6 +683,9 @@ class ListWheelScrollView extends StatefulWidget { /// {@macro flutter.rendering.wheelList.magnification} final double magnification; + /// {@macro flutter.rendering.wheelList.overAndUnderCenterOpacity} + final double overAndUnderCenterOpacity; + /// Size of each child in the main axis. Must not be null and must be /// positive. final double itemExtent; @@ -757,6 +766,7 @@ class _ListWheelScrollViewState extends State { offAxisFraction: widget.offAxisFraction, useMagnifier: widget.useMagnifier, magnification: widget.magnification, + overAndUnderCenterOpacity: widget.overAndUnderCenterOpacity, itemExtent: widget.itemExtent, squeeze: widget.squeeze, clipToSize: widget.clipToSize, @@ -952,6 +962,7 @@ class ListWheelViewport extends RenderObjectWidget { this.offAxisFraction = 0.0, this.useMagnifier = false, this.magnification = 1.0, + this.overAndUnderCenterOpacity = 1.0, @required this.itemExtent, this.squeeze = 1.0, this.clipToSize = true, @@ -965,6 +976,8 @@ class ListWheelViewport extends RenderObjectWidget { assert(perspective != null), assert(perspective > 0), assert(perspective <= 0.01, RenderListWheelViewport.perspectiveTooHighMessage), + assert(overAndUnderCenterOpacity != null), + assert(overAndUnderCenterOpacity >= 0 && overAndUnderCenterOpacity <= 1), assert(itemExtent != null), assert(itemExtent > 0), assert(squeeze != null), @@ -992,6 +1005,9 @@ class ListWheelViewport extends RenderObjectWidget { /// {@macro flutter.rendering.wheelList.magnification} final double magnification; + /// {@macro flutter.rendering.wheelList.overAndUnderCenterOpacity} + final double overAndUnderCenterOpacity; + /// {@macro flutter.rendering.wheelList.itemExtent} final double itemExtent; @@ -1027,6 +1043,7 @@ class ListWheelViewport extends RenderObjectWidget { offAxisFraction: offAxisFraction, useMagnifier: useMagnifier, magnification: magnification, + overAndUnderCenterOpacity: overAndUnderCenterOpacity, itemExtent: itemExtent, squeeze: squeeze, clipToSize: clipToSize, @@ -1043,6 +1060,7 @@ class ListWheelViewport extends RenderObjectWidget { ..offAxisFraction = offAxisFraction ..useMagnifier = useMagnifier ..magnification = magnification + ..overAndUnderCenterOpacity = overAndUnderCenterOpacity ..itemExtent = itemExtent ..squeeze = squeeze ..clipToSize = clipToSize diff --git a/packages/flutter/test/cupertino/date_picker_test.dart b/packages/flutter/test/cupertino/date_picker_test.dart index 9ce72720bd..701febc9d7 100644 --- a/packages/flutter/test/cupertino/date_picker_test.dart +++ b/packages/flutter/test/cupertino/date_picker_test.dart @@ -115,19 +115,20 @@ void main() { ); final Iterable pickers = tester.allWidgets.whereType(); - expect(pickers.any((CupertinoPicker picker) => picker.backgroundColor != CupertinoColors.white), false); + expect(pickers.any((CupertinoPicker picker) => picker.backgroundColor != null), false); }); - testWidgets('background color is not null', (WidgetTester tester) async { - expect( - () { - CupertinoTimerPicker( + testWidgets('background color can be null', (WidgetTester tester) async { + await tester.pumpWidget( + CupertinoApp( + home: CupertinoTimerPicker( onTimerDurationChanged: (_) { }, backgroundColor: null, - ); - }, - throwsAssertionError, + ), + ), ); + + expect(tester.takeException(), isNull); }); testWidgets('specified background color is applied', (WidgetTester tester) async { @@ -316,19 +317,20 @@ void main() { ); final Iterable pickers = tester.allWidgets.whereType(); - expect(pickers.any((CupertinoPicker picker) => picker.backgroundColor != CupertinoColors.white), false); + expect(pickers.any((CupertinoPicker picker) => picker.backgroundColor != null), false); }); - testWidgets('background color is not null', (WidgetTester tester) async { - expect( - () { - CupertinoDatePicker( + testWidgets('background color can be null', (WidgetTester tester) async { + await tester.pumpWidget( + CupertinoApp( + home: CupertinoDatePicker( onDateTimeChanged: (_) { }, backgroundColor: null, - ); - }, - throwsAssertionError, + ), + ), ); + + expect(tester.takeException(), isNull); }); testWidgets('specified background color is applied', (WidgetTester tester) async { diff --git a/packages/flutter/test/cupertino/picker_test.dart b/packages/flutter/test/cupertino/picker_test.dart index b36fdba9cb..2d39125786 100644 --- a/packages/flutter/test/cupertino/picker_test.dart +++ b/packages/flutter/test/cupertino/picker_test.dart @@ -8,6 +8,8 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../rendering/mock_canvas.dart'; + void main() { testWidgets('Picker respects theme styling', (WidgetTester tester) async { await tester.pumpWidget( @@ -95,125 +97,56 @@ void main() { }); }); - group('gradient', () { - testWidgets('gradient displays correctly with background color', (WidgetTester tester) async { - const Color backgroundColor = Color.fromRGBO(255, 0, 0, 1.0); - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: Align( - alignment: Alignment.topLeft, - child: SizedBox( - height: 300.0, - width: 300.0, - child: CupertinoPicker( - backgroundColor: backgroundColor, - itemExtent: 15.0, - children: const [ - Text('1'), - Text('1'), - Text('1'), - Text('1'), - Text('1'), - Text('1'), - Text('1'), - ], - onSelectedItemChanged: (int i) { }, + testWidgets('picker dark mode', (WidgetTester tester) async { + await tester.pumpWidget( + CupertinoApp( + theme: const CupertinoThemeData(brightness: Brightness.light), + home: Align( + alignment: Alignment.topLeft, + child: SizedBox( + height: 300.0, + width: 300.0, + child: CupertinoPicker( + backgroundColor: const CupertinoDynamicColor.withBrightness( + color: Color(0xFF123456), // Set alpha channel to FF to disable under magnifier painting. + darkColor: Color(0xFF654321), ), + itemExtent: 15.0, + children: const [Text('1'), Text('1')], + onSelectedItemChanged: (int i) { }, ), ), ), - ); - final Container container = tester.firstWidget(find.byType(Container)); - final BoxDecoration boxDecoration = container.decoration as BoxDecoration; - expect(boxDecoration.gradient.colors, [ - backgroundColor, - backgroundColor.withAlpha(0xF2), - backgroundColor.withAlpha(0xDD), - backgroundColor.withAlpha(0x00), - backgroundColor.withAlpha(0x00), - backgroundColor.withAlpha(0xDD), - backgroundColor.withAlpha(0xF2), - backgroundColor, - ]); - }); + ), + ); - testWidgets('No gradient displays with transparent background color', (WidgetTester tester) async { - const Color backgroundColor = Color.fromRGBO(255, 0, 0, 0.5); - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: Align( - alignment: Alignment.topLeft, - child: SizedBox( - height: 300.0, - width: 300.0, - child: CupertinoPicker( - backgroundColor: backgroundColor, - itemExtent: 15.0, - children: const [ - Text('1'), - Text('1'), - Text('1'), - Text('1'), - Text('1'), - Text('1'), - Text('1'), - ], - onSelectedItemChanged: (int i) { }, - ), - ), - ), - ), - ); - final DecoratedBox decoratedBox = tester.firstWidget(find.byType(DecoratedBox)); - final BoxDecoration boxDecoration = decoratedBox.decoration as BoxDecoration; - expect(boxDecoration.gradient, isNull); - expect(boxDecoration.color, isNotNull); - }); + expect(find.byType(CupertinoPicker), paints..path(color: const Color(0x33000000), style: PaintingStyle.stroke)); + expect(find.byType(CupertinoPicker), paints..rect(color: const Color(0xFF123456))); - testWidgets('gradient displays correctly with null background color', (WidgetTester tester) async { - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: Align( - alignment: Alignment.topLeft, - child: SizedBox( - height: 300.0, - width: 300.0, - child: CupertinoPicker( - backgroundColor: null, - itemExtent: 15.0, - children: const [ - Text('1'), - Text('1'), - Text('1'), - Text('1'), - Text('1'), - Text('1'), - Text('1'), - ], - onSelectedItemChanged: (int i) { }, + await tester.pumpWidget( + CupertinoApp( + theme: const CupertinoThemeData(brightness: Brightness.dark), + home: Align( + alignment: Alignment.topLeft, + child: SizedBox( + height: 300.0, + width: 300.0, + child: CupertinoPicker( + backgroundColor: const CupertinoDynamicColor.withBrightness( + color: Color(0xFF123456), + darkColor: Color(0xFF654321), ), + itemExtent: 15.0, + children: const [Text('1'), Text('1')], + onSelectedItemChanged: (int i) { }, ), ), ), - ); - // If the background color is null, the gradient color should be white. - const Color backgroundColor = Color(0xFFFFFFFF); - final Container container = tester.firstWidget(find.byType(Container)); - final BoxDecoration boxDecoration = container.decoration as BoxDecoration; - expect(boxDecoration.gradient.colors, [ - backgroundColor, - backgroundColor.withAlpha(0xF2), - backgroundColor.withAlpha(0xDD), - backgroundColor.withAlpha(0x00), - backgroundColor.withAlpha(0x00), - backgroundColor.withAlpha(0xDD), - backgroundColor.withAlpha(0xF2), - backgroundColor, - ]); - }); + ), + ); + + expect(find.byType(CupertinoPicker), paints..path(color: const Color(0x33FFFFFF), style: PaintingStyle.stroke)); + expect(find.byType(CupertinoPicker), paints..rect(color: const Color(0xFF654321))); }); group('scroll', () { diff --git a/packages/flutter/test/widgets/list_wheel_scroll_view_test.dart b/packages/flutter/test/widgets/list_wheel_scroll_view_test.dart index 5517569404..d871f17f92 100644 --- a/packages/flutter/test/widgets/list_wheel_scroll_view_test.dart +++ b/packages/flutter/test/widgets/list_wheel_scroll_view_test.dart @@ -64,6 +64,63 @@ void main() { throwsAssertionError, ); }); + + testWidgets('ListWheelScrollView needs valid overAndUnderCenterOpacity', (WidgetTester tester) async { + expect( + () { + ListWheelScrollView( + overAndUnderCenterOpacity: null, + itemExtent: 20.0, + children: [Container()], + ); + }, + throwsAssertionError, + ); + + expect( + () { + ListWheelScrollView( + overAndUnderCenterOpacity: -1, + itemExtent: 20.0, + children: [Container()], + ); + }, + throwsAssertionError, + ); + + expect( + () { + ListWheelScrollView( + overAndUnderCenterOpacity: 2, + itemExtent: 20.0, + children: [Container()], + ); + }, + throwsAssertionError, + ); + + expect( + () { + ListWheelScrollView( + overAndUnderCenterOpacity: 1, + itemExtent: 20.0, + children: [Container()], + ); + }, + isNot(throwsAssertionError), + ); + + expect( + () { + ListWheelScrollView( + overAndUnderCenterOpacity: 0, + itemExtent: 20.0, + children: [Container()], + ); + }, + isNot(throwsAssertionError), + ); + }); }); group('infinite scrolling', () {