diff --git a/example/lib/main.dart b/example/lib/main.dart index 7cc7a72..8c7f8de 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -27,13 +27,14 @@ class _MyHomePageState extends State { @override Widget build(BuildContext context) { return DefaultTabController( - length: 2, + length: 3, child: Scaffold( appBar: AppBar( bottom: TabBar( tabs: [ Tab(text: 'Integer'), Tab(text: 'Decimal'), + Tab(text: 'List'), ], ), title: Text('Numberpicker example'), @@ -42,6 +43,7 @@ class _MyHomePageState extends State { children: [ _IntegerExample(), _DecimalExample(), + _ListExample(), ], ), ), @@ -161,3 +163,54 @@ class __DecimalExampleState extends State<_DecimalExample> { ); } } + +class _ListExample extends StatefulWidget { + @override + __ListExampleState createState() => __ListExampleState(); +} + +class __ListExampleState extends State<_ListExample> { + final List valuesList = [10, 30, 20, 40, 55, 1, 2, 3, 4, 5, 76, 75, 74, 73]; + int _currentIndex = 3; + + int get _currentIntValue => valuesList[_currentIndex]; + + @override + Widget build(BuildContext context) { + return Column( + children: [ + SizedBox(height: 16), + Text('List', style: Theme.of(context).textTheme.headline6), + NumberPicker.fromList( + valuesList: valuesList, + value: _currentIndex, + haptics: true, + onChanged: (index) => setState(() { + _currentIndex = index; + }), + ), + SizedBox(height: 32), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + IconButton( + icon: Icon(Icons.remove), + onPressed: () => setState(() { + final newIndex = _currentIndex - 1; + _currentIndex = newIndex.clamp(0, valuesList.length - 1); + }), + ), + Text('Current int value: $_currentIntValue'), + IconButton( + icon: Icon(Icons.add), + onPressed: () => setState(() { + final newIndex = _currentIndex + 2; + _currentIndex = newIndex.clamp(0, valuesList.length - 1); + }), + ), + ], + ), + ], + ); + } +} diff --git a/lib/src/numberpicker.dart b/lib/src/numberpicker.dart index 63b97a1..7dc960d 100644 --- a/lib/src/numberpicker.dart +++ b/lib/src/numberpicker.dart @@ -13,6 +13,7 @@ class NumberPicker extends StatefulWidget { final int maxValue; /// Currently selected value + /// Will be the index if a list is being used (isFromList == true) final int value; /// Called when selected value changes @@ -57,6 +58,13 @@ class NumberPicker extends StatefulWidget { final bool infiniteLoop; + /// List of values to choose from. + /// Will be empty by default (if isFromList == false) + final List valuesList; + + /// Indicates if values are will be selected from valuesList or not. + final bool isFromList; + const NumberPicker({ Key? key, required this.minValue, @@ -77,6 +85,32 @@ class NumberPicker extends StatefulWidget { this.infiniteLoop = false, }) : assert(minValue <= value), assert(value <= maxValue), + this.valuesList = const [], + this.isFromList = false, + super(key: key); + + const NumberPicker.fromList({ + Key? key, + required this.valuesList, + required this.value, + required this.onChanged, + this.itemCount = 3, + this.itemHeight = 50, + this.itemWidth = 100, + this.axis = Axis.vertical, + this.textStyle, + this.selectedTextStyle, + this.haptics = false, + this.decoration, + this.zeroPad = false, + this.textMapper, + this.infiniteLoop = false, + }) : assert(0 <= value), + assert(value <= valuesList.length - 1), + this.minValue = 0, + this.maxValue = valuesList.length - 1, + this.step = 1, + this.isFromList = true, super(key: key); @override @@ -107,8 +141,9 @@ class _NumberPickerState extends State { } else { indexOfMiddleElement = indexOfMiddleElement.clamp(0, itemCount - 1); } - final intValueInTheMiddle = - _intValueFromIndex(indexOfMiddleElement + additionalItemsOnEachSide); + final intValueInTheMiddle = widget.isFromList + ? _correctIndex(indexOfMiddleElement + additionalItemsOnEachSide) + : _intValueFromIndex(indexOfMiddleElement + additionalItemsOnEachSide); if (widget.value != intValueInTheMiddle) { widget.onChanged(intValueInTheMiddle); @@ -118,7 +153,7 @@ class _NumberPickerState extends State { } Future.delayed( Duration(milliseconds: 100), - () => _maybeCenterValue(), + () => _maybeCenterValue(), ); } @@ -199,7 +234,9 @@ class _NumberPickerState extends State { final selectedStyle = widget.selectedTextStyle ?? themeData.textTheme.headline5?.copyWith(color: themeData.accentColor); - final value = _intValueFromIndex(index % itemCount); + final value = widget.isFromList + ? _correctIndex(index % itemCount) + : _intValueFromIndex(index % itemCount); final isExtra = !widget.infiniteLoop && (index < additionalItemsOnEachSide || index >= listItemsCount - additionalItemsOnEachSide); @@ -208,9 +245,9 @@ class _NumberPickerState extends State { final child = isExtra ? SizedBox.shrink() : Text( - _getDisplayedValue(value), - style: itemStyle, - ); + _getDisplayedValue(value), + style: itemStyle, + ); return Container( width: widget.itemWidth, @@ -221,6 +258,10 @@ class _NumberPickerState extends State { } String _getDisplayedValue(int value) { + if (widget.isFromList) { + value = _intValueFromList(value); + } + final text = widget.zeroPad ? value.toString().padLeft(widget.maxValue.toString().length, '0') : value.toString(); @@ -231,9 +272,19 @@ class _NumberPickerState extends State { } } - int _intValueFromIndex(int index) { + int _correctIndex(int index) { index -= additionalItemsOnEachSide; index %= itemCount; + return index; + } + + int _intValueFromList(int index) { + index = _correctIndex(index); + return widget.valuesList[index]; + } + + int _intValueFromIndex(int index) { + index = _correctIndex(index); return widget.minValue + index * widget.step; }