Unverified Commit 8cfc9246 authored by xster's avatar xster Committed by GitHub

CupertinoPicker fidelity revision (#31464)

parent 9e51e13e
09ebc5361187e9cc20ddc350dc047f95812c61a4 8057c8e1e0276a2ae7c26a0e04d54f339f3c51ca
...@@ -95,8 +95,8 @@ class _CupertinoPickerDemoState extends State<CupertinoPickerDemo> { ...@@ -95,8 +95,8 @@ class _CupertinoPickerDemoState extends State<CupertinoPickerDemo> {
setState(() => _selectedColorIndex = index); setState(() => _selectedColorIndex = index);
}, },
children: List<Widget>.generate(coolColorNames.length, (int index) { children: List<Widget>.generate(coolColorNames.length, (int index) {
return Center(child: return Center(
Text(coolColorNames[index]), child: Text(coolColorNames[index]),
); );
}), }),
), ),
......
...@@ -142,6 +142,10 @@ abstract class CupertinoLocalizations { ...@@ -142,6 +142,10 @@ abstract class CupertinoLocalizations {
// The global version uses the translated string from the arb file. // The global version uses the translated string from the arb file.
String get postMeridiemAbbreviation; String get postMeridiemAbbreviation;
/// Label shown in date pickers when the date is today.
// The global version uses the translated string from the arb file.
String get todayLabel;
/// The term used by the system to announce dialog alerts. /// The term used by the system to announce dialog alerts.
// The global version uses the translated string from the arb file. // The global version uses the translated string from the arb file.
String get alertDialogLabel; String get alertDialogLabel;
...@@ -338,6 +342,9 @@ class DefaultCupertinoLocalizations implements CupertinoLocalizations { ...@@ -338,6 +342,9 @@ class DefaultCupertinoLocalizations implements CupertinoLocalizations {
@override @override
String get postMeridiemAbbreviation => 'PM'; String get postMeridiemAbbreviation => 'PM';
@override
String get todayLabel => 'Today';
@override @override
String get alertDialogLabel => 'Alert'; String get alertDialogLabel => 'Alert';
...@@ -354,10 +361,10 @@ class DefaultCupertinoLocalizations implements CupertinoLocalizations { ...@@ -354,10 +361,10 @@ class DefaultCupertinoLocalizations implements CupertinoLocalizations {
String timerPickerHourLabel(int hour) => hour == 1 ? 'hour' : 'hours'; String timerPickerHourLabel(int hour) => hour == 1 ? 'hour' : 'hours';
@override @override
String timerPickerMinuteLabel(int minute) => 'min'; String timerPickerMinuteLabel(int minute) => 'min.';
@override @override
String timerPickerSecondLabel(int second) => 'sec'; String timerPickerSecondLabel(int second) => 'sec.';
@override @override
String get cutButtonLabel => 'Cut'; String get cutButtonLabel => 'Cut';
......
...@@ -7,13 +7,16 @@ import 'package:flutter/rendering.dart'; ...@@ -7,13 +7,16 @@ import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'theme.dart';
/// Color of the 'magnifier' lens border. /// Color of the 'magnifier' lens border.
const Color _kHighlighterBorder = Color(0xFF7F7F7F); const Color _kHighlighterBorder = Color(0xFF7F7F7F);
const Color _kDefaultBackground = Color(0xFFD2D4DB); const Color _kDefaultBackground = Color(0xFFD2D4DB);
// Eyeballed values comparing with a native picker. // Eyeballed values comparing with a native picker to produce the right
// Values closer to PI produces denser flatter lists. // curvatures and densities.
const double _kDefaultDiameterRatio = 1.35; const double _kDefaultDiameterRatio = 1.07;
const double _kDefaultPerspective = 0.004; const double _kDefaultPerspective = 0.003;
const double _kSqueeze = 1.45;
/// Opacity fraction value that hides the wheel above and below the 'magnifier' /// Opacity fraction value that hides the wheel above and below the 'magnifier'
/// lens with the same color as the background. /// lens with the same color as the background.
const double _kForegroundScreenOpacityFraction = 0.7; const double _kForegroundScreenOpacityFraction = 0.7;
...@@ -26,6 +29,11 @@ const double _kForegroundScreenOpacityFraction = 0.7; ...@@ -26,6 +29,11 @@ const double _kForegroundScreenOpacityFraction = 0.7;
/// Can be used with [showCupertinoModalPopup] to display the picker modally at the /// Can be used with [showCupertinoModalPopup] to display the picker modally at the
/// bottom of the screen. /// bottom of the screen.
/// ///
/// Sizes itself to its parent. All children are sized to the same size based
/// on [itemExtent].
///
/// By default, descendent texts are shown with [CupertinoTextThemeData.pickerTextStyle].
///
/// See also: /// See also:
/// ///
/// * [ListWheelScrollView], the generic widget backing this picker without /// * [ListWheelScrollView], the generic widget backing this picker without
...@@ -58,6 +66,7 @@ class CupertinoPicker extends StatefulWidget { ...@@ -58,6 +66,7 @@ class CupertinoPicker extends StatefulWidget {
this.useMagnifier = false, this.useMagnifier = false,
this.magnification = 1.0, this.magnification = 1.0,
this.scrollController, this.scrollController,
this.squeeze = _kSqueeze,
@required this.itemExtent, @required this.itemExtent,
@required this.onSelectedItemChanged, @required this.onSelectedItemChanged,
@required List<Widget> children, @required List<Widget> children,
...@@ -68,6 +77,8 @@ class CupertinoPicker extends StatefulWidget { ...@@ -68,6 +77,8 @@ class CupertinoPicker extends StatefulWidget {
assert(magnification > 0), assert(magnification > 0),
assert(itemExtent != null), assert(itemExtent != null),
assert(itemExtent > 0), assert(itemExtent > 0),
assert(squeeze != null),
assert(squeeze > 0),
childDelegate = looping childDelegate = looping
? ListWheelChildLoopingListDelegate(children: children) ? ListWheelChildLoopingListDelegate(children: children)
: ListWheelChildListDelegate(children: children), : ListWheelChildListDelegate(children: children),
...@@ -98,6 +109,7 @@ class CupertinoPicker extends StatefulWidget { ...@@ -98,6 +109,7 @@ class CupertinoPicker extends StatefulWidget {
this.useMagnifier = false, this.useMagnifier = false,
this.magnification = 1.0, this.magnification = 1.0,
this.scrollController, this.scrollController,
this.squeeze = _kSqueeze,
@required this.itemExtent, @required this.itemExtent,
@required this.onSelectedItemChanged, @required this.onSelectedItemChanged,
@required IndexedWidgetBuilder itemBuilder, @required IndexedWidgetBuilder itemBuilder,
...@@ -108,6 +120,8 @@ class CupertinoPicker extends StatefulWidget { ...@@ -108,6 +120,8 @@ class CupertinoPicker extends StatefulWidget {
assert(magnification > 0), assert(magnification > 0),
assert(itemExtent != null), assert(itemExtent != null),
assert(itemExtent > 0), assert(itemExtent > 0),
assert(squeeze != null),
assert(squeeze > 0),
childDelegate = ListWheelChildBuilderDelegate(builder: itemBuilder, childCount: childCount), childDelegate = ListWheelChildBuilderDelegate(builder: itemBuilder, childCount: childCount),
super(key: key); super(key: key);
...@@ -151,6 +165,11 @@ class CupertinoPicker extends StatefulWidget { ...@@ -151,6 +165,11 @@ class CupertinoPicker extends StatefulWidget {
/// height. Must not be null and must be positive. /// height. Must not be null and must be positive.
final double itemExtent; final double itemExtent;
/// {@macro flutter.rendering.wheelList.squeeze}
///
/// Defaults to `1.45` fo visually mimic iOS.
final double squeeze;
/// An option callback when the currently centered item changes. /// An option callback when the currently centered item changes.
/// ///
/// Value changes when the item closest to the center changes. /// Value changes when the item closest to the center changes.
...@@ -313,28 +332,32 @@ class _CupertinoPickerState extends State<CupertinoPicker> { ...@@ -313,28 +332,32 @@ class _CupertinoPickerState extends State<CupertinoPicker> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
Widget result = Stack( Widget result = DefaultTextStyle(
children: <Widget>[ style: CupertinoTheme.of(context).textTheme.pickerTextStyle,
Positioned.fill( child: Stack(
child: _CupertinoPickerSemantics( children: <Widget>[
scrollController: widget.scrollController ?? _controller, Positioned.fill(
child: ListWheelScrollView.useDelegate( child: _CupertinoPickerSemantics(
controller: widget.scrollController ?? _controller, scrollController: widget.scrollController ?? _controller,
physics: const FixedExtentScrollPhysics(), child: ListWheelScrollView.useDelegate(
diameterRatio: widget.diameterRatio, controller: widget.scrollController ?? _controller,
perspective: _kDefaultPerspective, physics: const FixedExtentScrollPhysics(),
offAxisFraction: widget.offAxisFraction, diameterRatio: widget.diameterRatio,
useMagnifier: widget.useMagnifier, perspective: _kDefaultPerspective,
magnification: widget.magnification, offAxisFraction: widget.offAxisFraction,
itemExtent: widget.itemExtent, useMagnifier: widget.useMagnifier,
onSelectedItemChanged: _handleSelectedItemChanged, magnification: widget.magnification,
childDelegate: widget.childDelegate, itemExtent: widget.itemExtent,
squeeze: widget.squeeze,
onSelectedItemChanged: _handleSelectedItemChanged,
childDelegate: widget.childDelegate,
),
), ),
), ),
), _buildGradientScreen(),
_buildGradientScreen(), _buildMagnifierScreen(),
_buildMagnifierScreen(), ],
], ),
); );
// Adds the appropriate opacity under the magnifier if the background // Adds the appropriate opacity under the magnifier if the background
// color is transparent. // color is transparent.
......
...@@ -83,6 +83,46 @@ const TextStyle _kDefaultLargeTitleDarkTextStyle = TextStyle( ...@@ -83,6 +83,46 @@ const TextStyle _kDefaultLargeTitleDarkTextStyle = TextStyle(
color: CupertinoColors.white, color: CupertinoColors.white,
); );
// Eyeballed value since it's not documented in https://developer.apple.com/design/resources/.
const TextStyle _kDefaultPickerLightTextStyle = TextStyle(
inherit: false,
fontFamily: '.SF Pro Display',
fontSize: 25.0,
fontWeight: FontWeight.w400,
letterSpacing: -0.41,
color: CupertinoColors.black,
);
// Eyeballed value since it's not documented in https://developer.apple.com/design/resources/.
const TextStyle _kDefaultPickerDarkTextStyle = TextStyle(
inherit: false,
fontFamily: '.SF Pro Display',
fontSize: 25.0,
fontWeight: FontWeight.w400,
letterSpacing: -0.41,
color: CupertinoColors.white,
);
// Eyeballed value since it's not documented in https://developer.apple.com/design/resources/.
const TextStyle _kDefaultDateTimePickerLightTextStyle = TextStyle(
inherit: false,
fontFamily: '.SF Pro Display',
fontSize: 21,
fontWeight: FontWeight.w300,
letterSpacing: -1.05,
color: CupertinoColors.black,
);
// Eyeballed value since it's not documented in https://developer.apple.com/design/resources/.
const TextStyle _kDefaultDateTimePickerDarkTextStyle = TextStyle(
inherit: false,
fontFamily: '.SF Pro Display',
fontSize: 21,
fontWeight: FontWeight.w300,
letterSpacing: -1.05,
color: CupertinoColors.white,
);
/// Cupertino typography theme in a [CupertinoThemeData]. /// Cupertino typography theme in a [CupertinoThemeData].
@immutable @immutable
class CupertinoTextThemeData extends Diagnosticable { class CupertinoTextThemeData extends Diagnosticable {
...@@ -104,6 +144,8 @@ class CupertinoTextThemeData extends Diagnosticable { ...@@ -104,6 +144,8 @@ class CupertinoTextThemeData extends Diagnosticable {
TextStyle navTitleTextStyle, TextStyle navTitleTextStyle,
TextStyle navLargeTitleTextStyle, TextStyle navLargeTitleTextStyle,
TextStyle navActionTextStyle, TextStyle navActionTextStyle,
TextStyle pickerTextStyle,
TextStyle dateTimePickerTextStyle,
}) : _primaryColor = primaryColor ?? CupertinoColors.activeBlue, }) : _primaryColor = primaryColor ?? CupertinoColors.activeBlue,
_brightness = brightness, _brightness = brightness,
_textStyle = textStyle, _textStyle = textStyle,
...@@ -111,7 +153,9 @@ class CupertinoTextThemeData extends Diagnosticable { ...@@ -111,7 +153,9 @@ class CupertinoTextThemeData extends Diagnosticable {
_tabLabelTextStyle = tabLabelTextStyle, _tabLabelTextStyle = tabLabelTextStyle,
_navTitleTextStyle = navTitleTextStyle, _navTitleTextStyle = navTitleTextStyle,
_navLargeTitleTextStyle = navLargeTitleTextStyle, _navLargeTitleTextStyle = navLargeTitleTextStyle,
_navActionTextStyle = navActionTextStyle; _navActionTextStyle = navActionTextStyle,
_pickerTextStyle = pickerTextStyle,
_dateTimePickerTextStyle = dateTimePickerTextStyle;
final Color _primaryColor; final Color _primaryColor;
final Brightness _brightness; final Brightness _brightness;
...@@ -155,6 +199,20 @@ class CupertinoTextThemeData extends Diagnosticable { ...@@ -155,6 +199,20 @@ class CupertinoTextThemeData extends Diagnosticable {
); );
} }
final TextStyle _pickerTextStyle;
/// Typography of pickers.
TextStyle get pickerTextStyle {
return _pickerTextStyle ??
(_isLight ? _kDefaultPickerLightTextStyle : _kDefaultPickerDarkTextStyle);
}
final TextStyle _dateTimePickerTextStyle;
/// Typography of date time pickers.
TextStyle get dateTimePickerTextStyle {
return _dateTimePickerTextStyle ??
(_isLight ? _kDefaultDateTimePickerLightTextStyle : _kDefaultDateTimePickerDarkTextStyle);
}
/// Returns a copy of the current [CupertinoTextThemeData] instance with /// Returns a copy of the current [CupertinoTextThemeData] instance with
/// specified overrides. /// specified overrides.
CupertinoTextThemeData copyWith({ CupertinoTextThemeData copyWith({
...@@ -166,6 +224,8 @@ class CupertinoTextThemeData extends Diagnosticable { ...@@ -166,6 +224,8 @@ class CupertinoTextThemeData extends Diagnosticable {
TextStyle navTitleTextStyle, TextStyle navTitleTextStyle,
TextStyle navLargeTitleTextStyle, TextStyle navLargeTitleTextStyle,
TextStyle navActionTextStyle, TextStyle navActionTextStyle,
TextStyle pickerTextStyle,
TextStyle dateTimePickerTextStyle,
}) { }) {
return CupertinoTextThemeData( return CupertinoTextThemeData(
primaryColor: primaryColor ?? _primaryColor, primaryColor: primaryColor ?? _primaryColor,
...@@ -176,6 +236,8 @@ class CupertinoTextThemeData extends Diagnosticable { ...@@ -176,6 +236,8 @@ class CupertinoTextThemeData extends Diagnosticable {
navTitleTextStyle: navTitleTextStyle ?? _navTitleTextStyle, navTitleTextStyle: navTitleTextStyle ?? _navTitleTextStyle,
navLargeTitleTextStyle: navLargeTitleTextStyle ?? _navLargeTitleTextStyle, navLargeTitleTextStyle: navLargeTitleTextStyle ?? _navLargeTitleTextStyle,
navActionTextStyle: navActionTextStyle ?? _navActionTextStyle, navActionTextStyle: navActionTextStyle ?? _navActionTextStyle,
pickerTextStyle: pickerTextStyle ?? _pickerTextStyle,
dateTimePickerTextStyle: dateTimePickerTextStyle ?? _dateTimePickerTextStyle,
); );
} }
} }
...@@ -137,10 +137,11 @@ class RenderListWheelViewport ...@@ -137,10 +137,11 @@ class RenderListWheelViewport
@required ViewportOffset offset, @required ViewportOffset offset,
double diameterRatio = defaultDiameterRatio, double diameterRatio = defaultDiameterRatio,
double perspective = defaultPerspective, double perspective = defaultPerspective,
double offAxisFraction = 0.0, double offAxisFraction = 0,
bool useMagnifier = false, bool useMagnifier = false,
double magnification = 1.0, double magnification = 1,
@required double itemExtent, @required double itemExtent,
double squeeze = 1,
bool clipToSize = true, bool clipToSize = true,
bool renderChildrenOutsideViewport = false, bool renderChildrenOutsideViewport = false,
List<RenderBox> children, List<RenderBox> children,
...@@ -156,6 +157,8 @@ class RenderListWheelViewport ...@@ -156,6 +157,8 @@ class RenderListWheelViewport
assert(magnification != null), assert(magnification != null),
assert(magnification > 0), assert(magnification > 0),
assert(itemExtent != null), assert(itemExtent != null),
assert(squeeze != null),
assert(squeeze > 0),
assert(itemExtent > 0), assert(itemExtent > 0),
assert(clipToSize != null), assert(clipToSize != null),
assert(renderChildrenOutsideViewport != null), assert(renderChildrenOutsideViewport != null),
...@@ -170,6 +173,7 @@ class RenderListWheelViewport ...@@ -170,6 +173,7 @@ class RenderListWheelViewport
_useMagnifier = useMagnifier, _useMagnifier = useMagnifier,
_magnification = magnification, _magnification = magnification,
_itemExtent = itemExtent, _itemExtent = itemExtent,
_squeeze = squeeze,
_clipToSize = clipToSize, _clipToSize = clipToSize,
_renderChildrenOutsideViewport = renderChildrenOutsideViewport { _renderChildrenOutsideViewport = renderChildrenOutsideViewport {
addAll(children); addAll(children);
...@@ -381,6 +385,39 @@ class RenderListWheelViewport ...@@ -381,6 +385,39 @@ class RenderListWheelViewport
markNeedsLayout(); markNeedsLayout();
} }
/// {@template flutter.rendering.wheelList.squeeze}
/// The angular compactness of the children on the wheel.
///
/// This denotes a ratio of the number of children on the wheel vs the number
/// of children that would fit on a flat list of equivalent size, assuming
/// [diameterRatio] of 1.
///
/// For instance, if this RenderListWheelViewport has a height of 100px and
/// [itemExtent] is 20px, 5 items would fit on an equivalent flat list.
/// With a [squeeze] of 1, 5 items would also be shown in the
/// RenderListWheelViewport. With a [squeeze] of 2, 10 items would be shown
/// in the RenderListWheelViewport.
///
/// Changing this value will change the number of children built and shown
/// inside the wheel.
///
/// Must not be null and must be positive.
/// {@endtemplate}
///
/// Defaults to 1.
double get squeeze => _squeeze;
double _squeeze;
set squeeze(double value) {
assert(value != null);
assert(value > 0);
if (value == _squeeze)
return;
_squeeze = value;
markNeedsLayout();
markNeedsSemanticsUpdate();
}
/// {@template flutter.rendering.wheelList.clipToSize} /// {@template flutter.rendering.wheelList.clipToSize}
/// Whether to clip painted children to the inside of this viewport. /// Whether to clip painted children to the inside of this viewport.
/// ///
...@@ -614,7 +651,7 @@ class RenderListWheelViewport ...@@ -614,7 +651,7 @@ class RenderListWheelViewport
// The height, in pixel, that children will be visible and might be laid out // The height, in pixel, that children will be visible and might be laid out
// and painted. // and painted.
double visibleHeight = size.height; double visibleHeight = size.height * _squeeze;
// If renderChildrenOutsideViewport is true, we spawn extra children by // If renderChildrenOutsideViewport is true, we spawn extra children by
// doubling the visibility range, those that are in the backside of the // doubling the visibility range, those that are in the backside of the
// cylinder won't be painted anyway. // cylinder won't be painted anyway.
...@@ -769,7 +806,7 @@ class RenderListWheelViewport ...@@ -769,7 +806,7 @@ class RenderListWheelViewport
// Get child's center as a fraction of the viewport's height. // Get child's center as a fraction of the viewport's height.
final double fractionalY = final double fractionalY =
(untransformedPaintingCoordinates.dy + _itemExtent / 2.0) / size.height; (untransformedPaintingCoordinates.dy + _itemExtent / 2.0) / size.height;
final double angle = -(fractionalY - 0.5) * 2.0 * _maxVisibleRadian; final double angle = -(fractionalY - 0.5) * 2.0 * _maxVisibleRadian / squeeze;
// Don't paint the backside of the cylinder when // Don't paint the backside of the cylinder when
// renderChildrenOutsideViewport is true. Otherwise, only children within // renderChildrenOutsideViewport is true. Otherwise, only children within
// suitable angles (via _first/lastVisibleLayoutOffset) reach the paint // suitable angles (via _first/lastVisibleLayoutOffset) reach the paint
......
...@@ -576,6 +576,7 @@ class ListWheelScrollView extends StatefulWidget { ...@@ -576,6 +576,7 @@ class ListWheelScrollView extends StatefulWidget {
this.useMagnifier = false, this.useMagnifier = false,
this.magnification = 1.0, this.magnification = 1.0,
@required this.itemExtent, @required this.itemExtent,
this.squeeze = 1.0,
this.onSelectedItemChanged, this.onSelectedItemChanged,
this.clipToSize = true, this.clipToSize = true,
this.renderChildrenOutsideViewport = false, this.renderChildrenOutsideViewport = false,
...@@ -589,6 +590,8 @@ class ListWheelScrollView extends StatefulWidget { ...@@ -589,6 +590,8 @@ class ListWheelScrollView extends StatefulWidget {
assert(magnification > 0), assert(magnification > 0),
assert(itemExtent != null), assert(itemExtent != null),
assert(itemExtent > 0), assert(itemExtent > 0),
assert(squeeze != null),
assert(squeeze > 0),
assert(clipToSize != null), assert(clipToSize != null),
assert(renderChildrenOutsideViewport != null), assert(renderChildrenOutsideViewport != null),
assert( assert(
...@@ -610,6 +613,7 @@ class ListWheelScrollView extends StatefulWidget { ...@@ -610,6 +613,7 @@ class ListWheelScrollView extends StatefulWidget {
this.useMagnifier = false, this.useMagnifier = false,
this.magnification = 1.0, this.magnification = 1.0,
@required this.itemExtent, @required this.itemExtent,
this.squeeze = 1.0,
this.onSelectedItemChanged, this.onSelectedItemChanged,
this.clipToSize = true, this.clipToSize = true,
this.renderChildrenOutsideViewport = false, this.renderChildrenOutsideViewport = false,
...@@ -623,6 +627,8 @@ class ListWheelScrollView extends StatefulWidget { ...@@ -623,6 +627,8 @@ class ListWheelScrollView extends StatefulWidget {
assert(magnification > 0), assert(magnification > 0),
assert(itemExtent != null), assert(itemExtent != null),
assert(itemExtent > 0), assert(itemExtent > 0),
assert(squeeze != null),
assert(squeeze > 0),
assert(clipToSize != null), assert(clipToSize != null),
assert(renderChildrenOutsideViewport != null), assert(renderChildrenOutsideViewport != null),
assert( assert(
...@@ -675,6 +681,11 @@ class ListWheelScrollView extends StatefulWidget { ...@@ -675,6 +681,11 @@ class ListWheelScrollView extends StatefulWidget {
/// positive. /// positive.
final double itemExtent; final double itemExtent;
/// {@macro flutter.rendering.wheelList.squeeze}
///
/// Defaults to 1.
final double squeeze;
/// On optional listener that's called when the centered item changes. /// On optional listener that's called when the centered item changes.
final ValueChanged<int> onSelectedItemChanged; final ValueChanged<int> onSelectedItemChanged;
...@@ -747,6 +758,7 @@ class _ListWheelScrollViewState extends State<ListWheelScrollView> { ...@@ -747,6 +758,7 @@ class _ListWheelScrollViewState extends State<ListWheelScrollView> {
useMagnifier: widget.useMagnifier, useMagnifier: widget.useMagnifier,
magnification: widget.magnification, magnification: widget.magnification,
itemExtent: widget.itemExtent, itemExtent: widget.itemExtent,
squeeze: widget.squeeze,
clipToSize: widget.clipToSize, clipToSize: widget.clipToSize,
renderChildrenOutsideViewport: widget.renderChildrenOutsideViewport, renderChildrenOutsideViewport: widget.renderChildrenOutsideViewport,
offset: offset, offset: offset,
...@@ -941,6 +953,7 @@ class ListWheelViewport extends RenderObjectWidget { ...@@ -941,6 +953,7 @@ class ListWheelViewport extends RenderObjectWidget {
this.useMagnifier = false, this.useMagnifier = false,
this.magnification = 1.0, this.magnification = 1.0,
@required this.itemExtent, @required this.itemExtent,
this.squeeze = 1.0,
this.clipToSize = true, this.clipToSize = true,
this.renderChildrenOutsideViewport = false, this.renderChildrenOutsideViewport = false,
@required this.offset, @required this.offset,
...@@ -954,6 +967,8 @@ class ListWheelViewport extends RenderObjectWidget { ...@@ -954,6 +967,8 @@ class ListWheelViewport extends RenderObjectWidget {
assert(perspective <= 0.01, RenderListWheelViewport.perspectiveTooHighMessage), assert(perspective <= 0.01, RenderListWheelViewport.perspectiveTooHighMessage),
assert(itemExtent != null), assert(itemExtent != null),
assert(itemExtent > 0), assert(itemExtent > 0),
assert(squeeze != null),
assert(squeeze > 0),
assert(clipToSize != null), assert(clipToSize != null),
assert(renderChildrenOutsideViewport != null), assert(renderChildrenOutsideViewport != null),
assert( assert(
...@@ -980,6 +995,11 @@ class ListWheelViewport extends RenderObjectWidget { ...@@ -980,6 +995,11 @@ class ListWheelViewport extends RenderObjectWidget {
/// {@macro flutter.rendering.wheelList.itemExtent} /// {@macro flutter.rendering.wheelList.itemExtent}
final double itemExtent; final double itemExtent;
/// {@macro flutter.rendering.wheelList.squeeze}
///
/// Defaults to 1.
final double squeeze;
/// {@macro flutter.rendering.wheelList.clipToSize} /// {@macro flutter.rendering.wheelList.clipToSize}
final bool clipToSize; final bool clipToSize;
...@@ -1008,6 +1028,7 @@ class ListWheelViewport extends RenderObjectWidget { ...@@ -1008,6 +1028,7 @@ class ListWheelViewport extends RenderObjectWidget {
useMagnifier: useMagnifier, useMagnifier: useMagnifier,
magnification: magnification, magnification: magnification,
itemExtent: itemExtent, itemExtent: itemExtent,
squeeze: squeeze,
clipToSize: clipToSize, clipToSize: clipToSize,
renderChildrenOutsideViewport: renderChildrenOutsideViewport, renderChildrenOutsideViewport: renderChildrenOutsideViewport,
); );
...@@ -1023,6 +1044,7 @@ class ListWheelViewport extends RenderObjectWidget { ...@@ -1023,6 +1044,7 @@ class ListWheelViewport extends RenderObjectWidget {
..useMagnifier = useMagnifier ..useMagnifier = useMagnifier
..magnification = magnification ..magnification = magnification
..itemExtent = itemExtent ..itemExtent = itemExtent
..squeeze = squeeze
..clipToSize = clipToSize ..clipToSize = clipToSize
..renderChildrenOutsideViewport = renderChildrenOutsideViewport; ..renderChildrenOutsideViewport = renderChildrenOutsideViewport;
} }
......
...@@ -3,10 +3,47 @@ ...@@ -3,10 +3,47 @@
// found in the LICENSE file. // found in the LICENSE file.
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
void main() { void main() {
testWidgets('Picker respects theme styling', (WidgetTester tester) async {
await tester.pumpWidget(
CupertinoApp(
home: Align(
alignment: Alignment.topLeft,
child: SizedBox(
height: 300.0,
width: 300.0,
child: CupertinoPicker(
itemExtent: 50.0,
onSelectedItemChanged: (_) { },
children: List<Widget>.generate(3, (int index) {
return Container(
height: 50.0,
width: 300.0,
child: Text(index.toString()),
);
}),
),
),
),
),
);
final RenderParagraph paragraph = tester.renderObject(find.text('1'));
expect(paragraph.text.style, const TextStyle(
inherit: false,
fontFamily: '.SF Pro Display',
fontSize: 25.0,
fontWeight: FontWeight.w400,
letterSpacing: -0.41,
color: CupertinoColors.black,
));
});
group('layout', () { group('layout', () {
testWidgets('selected item is in the middle', (WidgetTester tester) async { testWidgets('selected item is in the middle', (WidgetTester tester) async {
final FixedExtentScrollController controller = final FixedExtentScrollController controller =
......
...@@ -349,6 +349,51 @@ void main() { ...@@ -349,6 +349,51 @@ void main() {
// value of childCount should be 4. // value of childCount should be 4.
expect(viewport.childCount, 4); expect(viewport.childCount, 4);
}); });
testWidgets('a tighter squeeze lays out more children', (WidgetTester tester) async {
final FixedExtentScrollController controller =
FixedExtentScrollController(initialItem: 10);
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: ListWheelScrollView(
controller: controller,
itemExtent: 100.0,
onSelectedItemChanged: (_) { },
children: List<Widget>.generate(20, (int index) {
return Text(index.toString());
}),
),
)
);
final RenderListWheelViewport viewport = tester.firstRenderObject(find.byType(Text)).parent.parent;
// The screen is vertically 600px. Since the middle item is centered,
// half of the first and last items are visible, making 7 children visible.
expect(viewport.childCount, 7);
// Pump the same widget again but with double the squeeze.
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: ListWheelScrollView(
controller: controller,
itemExtent: 100.0,
squeeze: 2,
onSelectedItemChanged: (_) { },
children: List<Widget>.generate(20, (int index) {
return Text(index.toString());
}),
),
)
);
// 12 instead of 6 children are laid out + 1 because the middle item is
// centered.
expect(viewport.childCount, 13);
});
}); });
group('pre-transform viewport', () { group('pre-transform viewport', () {
......
...@@ -33,6 +33,11 @@ ...@@ -33,6 +33,11 @@
"description": "The abbreviation for post meridiem (after noon) shown in the time picker when it's not using the 24h format. Reference the text iOS uses such as in the iOS clock app." "description": "The abbreviation for post meridiem (after noon) shown in the time picker when it's not using the 24h format. Reference the text iOS uses such as in the iOS clock app."
}, },
"todayLabel": "Today",
"@todayLabel": {
"description": "A label shown in the date picker when the date is today."
},
"alertDialogLabel": "Alert", "alertDialogLabel": "Alert",
"@alertDialogLabel": { "@alertDialogLabel": {
"description": "The accessibility audio announcement made when an iOS style alert dialog is opened." "description": "The accessibility audio announcement made when an iOS style alert dialog is opened."
...@@ -45,15 +50,15 @@ ...@@ -45,15 +50,15 @@
"plural": "hour" "plural": "hour"
}, },
"timerPickerMinuteLabelOne": "min", "timerPickerMinuteLabelOne": "min.",
"timerPickerMinuteLabelOther": "min", "timerPickerMinuteLabelOther": "min.",
"@timerPickerMinuteLabel": { "@timerPickerMinuteLabel": {
"description": "The label adjacent to a minute integer number in a countdown timer. The reference abbreviation is what iOS does in the stock clock app's countdown timer.", "description": "The label adjacent to a minute integer number in a countdown timer. The reference abbreviation is what iOS does in the stock clock app's countdown timer.",
"plural": "minute" "plural": "minute"
}, },
"timerPickerSecondLabelOne": "sec", "timerPickerSecondLabelOne": "sec.",
"timerPickerSecondLabelOther": "sec", "timerPickerSecondLabelOther": "sec.",
"@timerPickerSecondLabel": { "@timerPickerSecondLabel": {
"description": "The label adjacent to a second integer number in a countdown timer. The reference abbreviation is what iOS does in the stock clock app's countdown timer.", "description": "The label adjacent to a second integer number in a countdown timer. The reference abbreviation is what iOS does in the stock clock app's countdown timer.",
"plural": "second" "plural": "second"
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
"datePickerDateTimeOrder": "date_time_dayPeriod", "datePickerDateTimeOrder": "date_time_dayPeriod",
"anteMeridiemAbbreviation": "AM", "anteMeridiemAbbreviation": "AM",
"postMeridiemAbbreviation": "PM", "postMeridiemAbbreviation": "PM",
"todayLabel": "aujourd'hui",
"alertDialogLabel": "Alerte", "alertDialogLabel": "Alerte",
"timerPickerHourLabelOne": "heure", "timerPickerHourLabelOne": "heure",
"timerPickerHourLabelOther": "heures", "timerPickerHourLabelOther": "heures",
......
...@@ -94,16 +94,19 @@ class CupertinoLocalizationEn extends GlobalCupertinoLocalizations { ...@@ -94,16 +94,19 @@ class CupertinoLocalizationEn extends GlobalCupertinoLocalizations {
String get timerPickerHourLabelOther => r'hours'; String get timerPickerHourLabelOther => r'hours';
@override @override
String get timerPickerMinuteLabelOne => r'min'; String get timerPickerMinuteLabelOne => r'min.';
@override @override
String get timerPickerMinuteLabelOther => r'min'; String get timerPickerMinuteLabelOther => r'min.';
@override @override
String get timerPickerSecondLabelOne => r'sec'; String get timerPickerSecondLabelOne => r'sec.';
@override @override
String get timerPickerSecondLabelOther => r'sec'; String get timerPickerSecondLabelOther => r'sec.';
@override
String get todayLabel => r'Today';
} }
/// The translations for French (`fr`). /// The translations for French (`fr`).
...@@ -189,6 +192,9 @@ class CupertinoLocalizationFr extends GlobalCupertinoLocalizations { ...@@ -189,6 +192,9 @@ class CupertinoLocalizationFr extends GlobalCupertinoLocalizations {
@override @override
String get timerPickerSecondLabelOther => r's'; String get timerPickerSecondLabelOther => r's';
@override
String get todayLabel => r'aujourd' "'" r'hui';
} }
/// The set of supported languages, as language code strings. /// The set of supported languages, as language code strings.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment