mirror of
https://github.com/Iconica-Development/flutter_input_library.git
synced 2025-05-18 17:03:45 +02:00
Merge pull request #23 from Iconica-Development/feature/scroll_picker
feat: Added scroll picker field
This commit is contained in:
commit
d0c0d49d66
11 changed files with 467 additions and 55 deletions
38
.github/workflows/flutter.yml
vendored
38
.github/workflows/flutter.yml
vendored
|
@ -1,32 +1,12 @@
|
|||
name: CI
|
||||
|
||||
name: Iconica Standard Component CI Workflow
|
||||
# Workflow Caller version: 2.0.0
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
- feature/*
|
||||
- bugfix/*
|
||||
- hotfix/*
|
||||
|
||||
workflow_dispatch:
|
||||
jobs:
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.gradle/wrapper
|
||||
/opt/hostedtoolcache/flutter
|
||||
key: ${{ runner.OS }}-flutter-install-cache
|
||||
- uses: subosito/flutter-action@v2
|
||||
with:
|
||||
channel: 'stable'
|
||||
- name: Flutter pub get
|
||||
run: flutter pub get
|
||||
- name: Dart format
|
||||
run: dart format -o none --set-exit-if-changed .
|
||||
- name: Flutter analyze
|
||||
run: flutter analyze
|
||||
call-global-iconica-workflow:
|
||||
uses: Iconica-Development/.github/.github/workflows/component-ci.yml@master
|
||||
secrets: inherit
|
||||
permissions: write-all
|
||||
with:
|
||||
subfolder: '.' # add optional subfolder to run workflow in
|
||||
|
|
|
@ -40,4 +40,7 @@
|
|||
|
||||
## 2.4.0
|
||||
* The ability to disable the onTap paramater of the DatePicker
|
||||
* FlutterFormInputDateTime now also had the enabled parameter to provide to DateTimeInputField
|
||||
* FlutterFormInputDateTime now also had the enabled parameter to provide to DateTimeInputField
|
||||
|
||||
## 2.5.0
|
||||
* Addition of the ScrollPicker input field.
|
|
@ -31,12 +31,15 @@ class MyHomePage extends StatefulWidget {
|
|||
}
|
||||
|
||||
class _MyHomePageState extends State<MyHomePage> {
|
||||
var weekDayDateFormat = DateFormat('EEEE');
|
||||
var monthDateFormat = DateFormat('MMMM');
|
||||
|
||||
var formKey = GlobalKey<FormState>();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
}
|
||||
var weekDays = TypeUtils().createWeekDays(WeekDay.monday, WeekDay.sunday);
|
||||
var dates =
|
||||
TypeUtils().createMonthList(Month.january, Month.december, year: 2023);
|
||||
var years = TypeUtils().createYearList(2000, 2023);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
@ -138,6 +141,42 @@ class _MyHomePageState extends State<MyHomePage> {
|
|||
},
|
||||
),
|
||||
Container(height: 50),
|
||||
const Text('FlutterFormInputScrollPicker: Weekdays'),
|
||||
const SizedBox(
|
||||
height: 8,
|
||||
),
|
||||
FlutterFormInputScrollPicker(
|
||||
values: weekDays,
|
||||
onChanged: (value) {},
|
||||
childToString: (s) =>
|
||||
s != null ? weekDayDateFormat.format(s) : '',
|
||||
decoration: const ScrollPickerDecoration(),
|
||||
),
|
||||
const Text('FlutterFormInputScrollPicker: Months'),
|
||||
const SizedBox(
|
||||
height: 8,
|
||||
),
|
||||
FlutterFormInputScrollPicker(
|
||||
values: dates,
|
||||
onChanged: (value) {},
|
||||
childToString: (s) =>
|
||||
s != null ? monthDateFormat.format(s) : '',
|
||||
decoration: const ScrollPickerDecoration(),
|
||||
),
|
||||
const Padding(
|
||||
padding: EdgeInsets.all(8.0),
|
||||
child: Divider(),
|
||||
),
|
||||
const Text('FlutterFormInputScrollPicker: Years'),
|
||||
const SizedBox(
|
||||
height: 8,
|
||||
),
|
||||
FlutterFormInputScrollPicker(
|
||||
values: years,
|
||||
onChanged: (value) {},
|
||||
childToString: (s) => s?.year.toString() ?? '',
|
||||
decoration: const ScrollPickerDecoration(),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
|
|
@ -37,10 +37,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: collection
|
||||
sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c"
|
||||
sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.17.1"
|
||||
version: "1.17.2"
|
||||
cupertino_icons:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -68,7 +68,7 @@ packages:
|
|||
path: ".."
|
||||
relative: true
|
||||
source: path
|
||||
version: "2.2.1"
|
||||
version: "2.4.0"
|
||||
flutter_lints:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
|
@ -90,14 +90,6 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.18.1"
|
||||
js:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: js
|
||||
sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.6.7"
|
||||
lints:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -110,18 +102,18 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: matcher
|
||||
sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb"
|
||||
sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.12.15"
|
||||
version: "0.12.16"
|
||||
material_color_utilities:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: material_color_utilities
|
||||
sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724
|
||||
sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.2.0"
|
||||
version: "0.5.0"
|
||||
meta:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -147,10 +139,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: source_span
|
||||
sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250
|
||||
sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.9.1"
|
||||
version: "1.10.0"
|
||||
stack_trace:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -187,10 +179,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: test_api
|
||||
sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb
|
||||
sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.5.1"
|
||||
version: "0.6.0"
|
||||
vector_math:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -199,6 +191,14 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.4"
|
||||
web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: web
|
||||
sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.1.4-beta"
|
||||
sdks:
|
||||
dart: ">=3.0.0-0 <4.0.0"
|
||||
dart: ">=3.1.0-185.0.dev <4.0.0"
|
||||
flutter: ">=1.17.0"
|
||||
|
|
|
@ -5,3 +5,4 @@ export 'text/plain_text.dart';
|
|||
export 'slider/slider.dart';
|
||||
export 'switch/switch.dart';
|
||||
export 'date_picker/date_picker.dart';
|
||||
export 'scroll_picker/scroll_picker.dart';
|
||||
|
|
3
lib/src/inputs/scroll_picker/scroll_picker.dart
Normal file
3
lib/src/inputs/scroll_picker/scroll_picker.dart
Normal file
|
@ -0,0 +1,3 @@
|
|||
export 'scroll_picker_widget.dart';
|
||||
export 'scroll_picker_decoration.dart';
|
||||
export 'scroll_picker_type_extensions.dart';
|
107
lib/src/inputs/scroll_picker/scroll_picker_decoration.dart
Normal file
107
lib/src/inputs/scroll_picker/scroll_picker_decoration.dart
Normal file
|
@ -0,0 +1,107 @@
|
|||
// SPDX-FileCopyrightText: 2023 Iconica
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class ScrollPickerDecoration {
|
||||
const ScrollPickerDecoration({
|
||||
this.scrollItemBuilder,
|
||||
this.highlightWidget,
|
||||
this.scrollItemTextStyle,
|
||||
this.numberOfVisibleItems = 5,
|
||||
this.itemHeight = 30,
|
||||
this.diameterRatio = 2.0,
|
||||
this.perspective = 0.002,
|
||||
this.overAndUnderCenterOpacity = 1.0,
|
||||
this.offAxisFraction = 0.0,
|
||||
this.useMagnifier = false,
|
||||
this.magnification = 1.0,
|
||||
this.squeeze = 1.0,
|
||||
this.renderChildrenOutsideViewport = false,
|
||||
});
|
||||
|
||||
/// Ability to provide your own builder for the scroll items
|
||||
final Widget Function(BuildContext context, int index, dynamic value)?
|
||||
scrollItemBuilder;
|
||||
|
||||
/// Override the standard highlight widget. (Grey container which is placed behind the selected item).
|
||||
final Widget? highlightWidget;
|
||||
|
||||
/// Textstyle of the scroll items. Will be overridden if the [scrollItemBuilder] is set.
|
||||
final TextStyle? scrollItemTextStyle;
|
||||
|
||||
/// Amount of visible items in the scroll wheel. Changing this changes the height of the widget.
|
||||
final int numberOfVisibleItems;
|
||||
|
||||
/// Height of each item in the scrollwheel. Chaging this changes the height of the widget.
|
||||
final double itemHeight;
|
||||
|
||||
/// A ratio between the diameter of the cylinder and the viewport's size in the main axis.
|
||||
///
|
||||
/// A value of 1 means the cylinder has the same diameter as the viewport's size.
|
||||
///
|
||||
/// A value smaller than 1 means items at the edges of the cylinder are entirely contained inside the viewport.
|
||||
///
|
||||
/// A value larger than 1 means angles less than ±[pi] / 2 from the center of the cylinder are visible.
|
||||
///
|
||||
/// The same number of children will be visible in the viewport regardless of the [diameterRatio]. The number of children visible is based on the viewport's length along the main axis divided by the children's [itemExtent]. Then the children are evenly distributed along the visible angles up to ±[pi] / 2.
|
||||
///
|
||||
/// Just as it's impossible to stretch a paper to cover the an entire half of a cylinder's surface where the cylinder has the same diameter as the paper's length, choosing a [diameterRatio] smaller than [pi] will leave same gaps between the children.
|
||||
///
|
||||
/// Defaults to an arbitrary but aesthetically reasonable number of 2.0.
|
||||
///
|
||||
/// Must not be null and must be positive.
|
||||
final double diameterRatio;
|
||||
|
||||
/// Size of each child in the main axis. Must not be null and must be positive.
|
||||
final double perspective;
|
||||
|
||||
/// 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.
|
||||
final double overAndUnderCenterOpacity;
|
||||
|
||||
/// How much the wheel is horizontally off-center, as a fraction of its width. This property creates the visual effect of looking at a vertical wheel from its side where its vanishing points at the edge curves to one side instead of looking at the wheel head-on.
|
||||
///
|
||||
/// The value is horizontal distance between the wheel's center and the vertical vanishing line at the edges of the wheel, represented as a fraction of the wheel's width.
|
||||
///
|
||||
/// The value 0.0 means the wheel is looked at head-on and its vanishing line runs through the center of the wheel. Negative values means moving the wheel to the left of the observer, thus the edges curve to the right. Positive values means moving the wheel to the right of the observer, thus the edges curve to the left.
|
||||
///
|
||||
/// The visual effect causes the wheel's edges to curve rather than moving the center. So a value of 0.5 means the edges' vanishing line will touch the wheel's size's left edge.
|
||||
///
|
||||
/// Defaults to 0.0, which means looking at the wheel head-on. The visual effect can be unaesthetic if this value is too far from the range [-0.5, 0.5].
|
||||
final double offAxisFraction;
|
||||
|
||||
/// Whether to use the magnifier for the center item of the wheel.
|
||||
final bool useMagnifier;
|
||||
|
||||
/// The zoomed-in rate of the magnifier, if it is used.
|
||||
///
|
||||
/// The default value is 1.0, which will not change anything. If the value is > 1.0, the center item will be zoomed in by that rate, and it will also be rendered as flat, not cylindrical like the rest of the list. The item will be zoomed out if magnification < 1.0.
|
||||
///
|
||||
/// Must be positive.
|
||||
final double magnification;
|
||||
|
||||
/// 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.
|
||||
///
|
||||
/// Defaults to 1.
|
||||
final double squeeze;
|
||||
|
||||
/// Whether to paint children inside the viewport only.
|
||||
///
|
||||
/// If false, every child will be painted. However the [Scrollable] is still the size of the viewport and detects gestures inside only.
|
||||
///
|
||||
/// Defaults to false. Must not be null. Cannot be true if [clipBehavior] is not [Clip.none] since children outside the viewport will be clipped, and therefore cannot render children outside the viewport.
|
||||
final bool renderChildrenOutsideViewport;
|
||||
}
|
126
lib/src/inputs/scroll_picker/scroll_picker_field.dart
Normal file
126
lib/src/inputs/scroll_picker/scroll_picker_field.dart
Normal file
|
@ -0,0 +1,126 @@
|
|||
// SPDX-FileCopyrightText: 2023 Iconica
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_input_library/src/inputs/scroll_picker/scroll_picker_decoration.dart';
|
||||
|
||||
class ScrollPicker extends StatefulWidget {
|
||||
const ScrollPicker({
|
||||
required this.list,
|
||||
required this.onChanged,
|
||||
required this.decoration,
|
||||
this.initialIndex,
|
||||
super.key,
|
||||
});
|
||||
|
||||
final List<String> list;
|
||||
final void Function(int index) onChanged;
|
||||
final ScrollPickerDecoration decoration;
|
||||
|
||||
final int? initialIndex;
|
||||
|
||||
@override
|
||||
State<ScrollPicker> createState() => _ScrollPickerState();
|
||||
}
|
||||
|
||||
class _ScrollPickerState extends State<ScrollPicker> {
|
||||
late FixedExtentScrollController scrollController;
|
||||
|
||||
late double pickerHeight;
|
||||
|
||||
late int selectedIndex;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
var initialIndex = widget.initialIndex;
|
||||
|
||||
if (initialIndex != null &&
|
||||
initialIndex > 0 &&
|
||||
initialIndex < widget.list.length) {
|
||||
selectedIndex = initialIndex;
|
||||
} else {
|
||||
selectedIndex = (widget.list.length / 2).floor();
|
||||
}
|
||||
|
||||
pickerHeight =
|
||||
widget.decoration.itemHeight * widget.decoration.numberOfVisibleItems;
|
||||
|
||||
scrollController = FixedExtentScrollController(
|
||||
initialItem: selectedIndex,
|
||||
);
|
||||
|
||||
scrollController.addListener(() {
|
||||
var newIndex =
|
||||
(scrollController.offset / widget.decoration.itemHeight).round();
|
||||
|
||||
if (newIndex != selectedIndex) {
|
||||
widget.onChanged.call(
|
||||
(scrollController.offset / widget.decoration.itemHeight).round());
|
||||
|
||||
selectedIndex = newIndex;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
scrollController.dispose();
|
||||
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Stack(
|
||||
children: [
|
||||
Positioned.fill(
|
||||
child: Center(
|
||||
child: widget.decoration.highlightWidget ??
|
||||
Container(
|
||||
height: widget.decoration.itemHeight,
|
||||
decoration: ShapeDecoration(
|
||||
color: Colors.grey.shade300,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(5),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: pickerHeight,
|
||||
child: ListWheelScrollView.useDelegate(
|
||||
physics: const FixedExtentScrollPhysics(),
|
||||
diameterRatio: widget.decoration.diameterRatio,
|
||||
itemExtent: widget.decoration.itemHeight,
|
||||
controller: scrollController,
|
||||
perspective: widget.decoration.perspective,
|
||||
overAndUnderCenterOpacity:
|
||||
widget.decoration.overAndUnderCenterOpacity,
|
||||
childDelegate: ListWheelChildBuilderDelegate(
|
||||
builder: (context, index) =>
|
||||
widget.decoration.scrollItemBuilder
|
||||
?.call(context, index, widget.list[index]) ??
|
||||
Center(
|
||||
child: Text(
|
||||
widget.list[index],
|
||||
style: widget.decoration.scrollItemTextStyle,
|
||||
),
|
||||
),
|
||||
childCount: widget.list.length,
|
||||
),
|
||||
offAxisFraction: widget.decoration.offAxisFraction,
|
||||
useMagnifier: widget.decoration.useMagnifier,
|
||||
magnification: widget.decoration.magnification,
|
||||
squeeze: widget.decoration.squeeze,
|
||||
renderChildrenOutsideViewport:
|
||||
widget.decoration.renderChildrenOutsideViewport,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
// SPDX-FileCopyrightText: 2023 Iconica
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
enum WeekDay {
|
||||
monday,
|
||||
tuesday,
|
||||
wednesday,
|
||||
thursday,
|
||||
friday,
|
||||
saturday,
|
||||
sunday,
|
||||
}
|
||||
|
||||
enum Month {
|
||||
january,
|
||||
february,
|
||||
march,
|
||||
april,
|
||||
may,
|
||||
june,
|
||||
july,
|
||||
august,
|
||||
september,
|
||||
october,
|
||||
november,
|
||||
december,
|
||||
}
|
||||
|
||||
class TypeUtils {
|
||||
/// Creates list of Datetime with days. These fall on the respective week days from start to end.
|
||||
List<DateTime> createWeekDays(
|
||||
WeekDay start,
|
||||
WeekDay end,
|
||||
) {
|
||||
if (start.index > end.index) {
|
||||
throw ArgumentError('Start month must be before or equal to end month.');
|
||||
}
|
||||
|
||||
List<DateTime> result = [];
|
||||
for (int i = start.index; i <= end.index; i++) {
|
||||
result.add(DateTime(2024, 1, WeekDay.values[i].index + 1));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Creates list of Datetime with the months from start to end.
|
||||
List<DateTime> createMonthList(Month start, Month end, {int? year}) {
|
||||
if (start.index > end.index) {
|
||||
throw ArgumentError('Start month must be before or equal to end month.');
|
||||
}
|
||||
|
||||
List<DateTime> result = [];
|
||||
for (int i = start.index; i <= end.index; i++) {
|
||||
result.add(
|
||||
DateTime(year ?? DateTime.now().year, Month.values[i].index + 1, 1));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Creates a list of Datetime with the years from start to end.
|
||||
List<DateTime> createYearList(int start, int end) {
|
||||
if (start > end) {
|
||||
throw ArgumentError('Start year must be before or equal to year month.');
|
||||
}
|
||||
|
||||
List<DateTime> result = [];
|
||||
for (int i = 0; i <= end - start; i++) {
|
||||
result.add(DateTime(start + i, 1, 1));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
77
lib/src/inputs/scroll_picker/scroll_picker_widget.dart
Normal file
77
lib/src/inputs/scroll_picker/scroll_picker_widget.dart
Normal file
|
@ -0,0 +1,77 @@
|
|||
// SPDX-FileCopyrightText: 2023 Iconica
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_input_library/src/inputs/scroll_picker/scroll_picker_decoration.dart';
|
||||
import 'package:flutter_input_library/src/inputs/scroll_picker/scroll_picker_field.dart';
|
||||
|
||||
class FlutterFormInputScrollPicker<T> extends StatelessWidget {
|
||||
const FlutterFormInputScrollPicker({
|
||||
required this.values,
|
||||
required this.decoration,
|
||||
required this.childToString,
|
||||
this.onSaved,
|
||||
this.onChanged,
|
||||
this.initialIndex = 0,
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
/// Values that will be shown in the scroll picker.
|
||||
final List<T> values;
|
||||
|
||||
/// Initial index to set the scroll picker too.
|
||||
final int? initialIndex;
|
||||
|
||||
/// Function called when the save function is called on the parent form.
|
||||
final Function(T?)? onSaved;
|
||||
|
||||
/// Function called when the value is changed by the user.
|
||||
final Function(T?)? onChanged;
|
||||
|
||||
/// Converts the given value to a String.
|
||||
final String Function(T?) childToString;
|
||||
|
||||
/// Decoration for the scroll picker.
|
||||
final ScrollPickerDecoration decoration;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ScrollPickerFormField<T>(
|
||||
values: values,
|
||||
initialIndex: initialIndex,
|
||||
decoration: decoration,
|
||||
childToString: childToString,
|
||||
onSaved: (value) => onSaved?.call(value),
|
||||
onChanged: (value) => onChanged?.call(value),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ScrollPickerFormField<T> extends FormField<T> {
|
||||
ScrollPickerFormField({
|
||||
required List<T> values,
|
||||
int? initialIndex,
|
||||
required ScrollPickerDecoration decoration,
|
||||
required FormFieldSetter<T> onSaved,
|
||||
void Function(T value)? onChanged,
|
||||
required String Function(T) childToString,
|
||||
Key? key,
|
||||
}) : super(
|
||||
key: key,
|
||||
onSaved: onSaved,
|
||||
initialValue: values[initialIndex ?? (values.length / 2).floor()],
|
||||
builder: (FormFieldState<T> state) {
|
||||
return ScrollPicker(
|
||||
list: values.map((e) => childToString(e)).toList(),
|
||||
decoration: decoration,
|
||||
initialIndex: initialIndex,
|
||||
onChanged: (int index) {
|
||||
onChanged?.call(values[index]);
|
||||
|
||||
state.didChange(values[index]);
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
name: flutter_input_library
|
||||
description: A new Flutter package project.
|
||||
version: 2.4.0
|
||||
version: 2.5.0
|
||||
repository: https://github.com/Iconica-Development/flutter_input_library
|
||||
|
||||
environment:
|
||||
|
|
Loading…
Reference in a new issue