0 purchases
spark form
Spark_Form #
简介 #
spark form 是一个flutter平台的表单快速成型框架,其内部包括以下几个部分
表单快速构建
表单数据校验及数据管理
自定义数据生成组件
基于主题的自定义样式
开放式组件及自定义接入组件
焦点管理工具
自定义时间日期选择器
自定义选择器
基于上述功能,可以快速进行flutter的表单应用的开发,减少不必要的功能编写
表单数据处理 #
FormGroupManage #
FormGroupManage是用于管理表单数据的生成及管理类,提供具名构造函数create
factory FormGroupManage.create(Map<String, ManageFieldItem> createField) =>
FormGroupManage._(createField);
copied to clipboard
接收的参数类型为Map<String, ManageFieldItem>其对应每一个字段所使用的组件类型的Option,并由 ManageFieldItem管理,你可以这样构建你的表单数据
final Map<String, ManageFieldItem> _fieldMap = {
'test1': ManageFieldItem(data: ''),
'test2': ManageFieldItem(
data: SparkLabelTitleData.from('hahshdh', 'change value')),
'test5': ManageFieldItem(data: '2'),
'select': ManageFieldItem(
data: List.generate(
5,
(index) => SparkTagGroupItem.from(
name: 'hh$index a',
data: '$index',
),
),
),
}
copied to clipboard
因为每一种组件所使用的数据类型不一致,所以在生成的时候,所对应的数据格式也不一致,以对应不同组件的数据生成,组件对应数据格式见每个组件的详细介绍
Tip: FormGroupManage必须生成在form构建之前
内部可以进行表单数据的获取
/// get json data
/// exclude field[excludeField]is not include in json data
Map getJson({List<String>? excludeField}) {
....
}
copied to clipboard
只需要调用此方法,即可得到转换后的数据,类型为Map结构,其对应关系与传入的转换数据一致,用于表单数据的生成
SparkFormDataChangeImp #
对于表单构建的数据,如果需要使用自定义数据,请继承实现,类包含两个字段,data为最后转换数据返回的数据,needSelected 为转化依据,只要当值为true时才会被转换
abstract class SparkFormDataChangeImp {
SparkFormDataChangeImp(this.data);
/// Serialized data
/// [FormManage.getJson] use this filed to create json data
dynamic data;
/// only true can use by [FormManage.getJson]
bool needSelected = false;
}
copied to clipboard
表单基础组件介绍 #
在基础组件中,应该遵循的封装原则是,组件可脱离form主体进行使用,即可单独使用
SparkForm #
表单组件,是一个表单的顶层组件,接收参数为
const SparkForm({
Key? key,
required this.child,
required this.manage,
this.controller,
}) : super(key: key);
/// form controller
final FormController? controller;
/// form item builder
final Widget child;
/// form data manage
final FormGroupManage manage;
copied to clipboard
在表单构建的时候,组件必须包裹在最外层,以提供SparkFormItem所需要的运行数据,组件接收一个SparkFormController作为内部控制器,可用于表单的校验和清除操作,见表单校验
SparkFormItem #
表单子组件。其功能包括 label 布局生成,焦点管理,校验错误内容提示,等功能,接收参数为
const SparkFormItem({
Key? key,
required this.fieldName,
required this.child,
this.direction,
this.labelBuilder,
this.label,
this.isRequired,
this.rules,
this.labelWidth,
this.lablePadding,
this.decoration,
this.readOnly = false,
this.padding,
this.margin,
this.labelStyle,
this.crossCenter,
this.errorStyle,
this.errorContentPadding,
this.labelSuffix,
}) : super(key: key);
/// form item bind field name
final String fieldName;
/// form label name
final String? label;
/// form label widget builder
final WidgetThemeBuilder? labelBuilder;
/// form widget builder
final Widget child;
/// form layout direction, set title layout in top or left
final Direction? direction;
/// form item is required
final bool? isRequired;
/// label width
final double? labelWidth;
/// setup label layout padding
final EdgeInsets? lablePadding;
/// form item decoration
final FocusDecoration? decoration;
/// value check rules
final List<SparkValidator>? rules;
/// set form item response focusNode
/// if false, focus style is not't change
/// [FocusPointerScope.shadow]
final bool? readOnly;
/// form item content padding
final EdgeInsets? padding;
/// form item content margin
final EdgeInsets? margin;
/// set label text style
final TextStyle? labelStyle;
/// cross use [CrossAxisAlignment.center]
final bool? crossCenter;
/// error tip message style
final TextStyle? errorStyle;
/// tip message content layout
final EdgeInsets? errorContentPadding;
/// label suffix, is left label text suffix
/// not form item right suffix
final Widget? labelSuffix;
copied to clipboard
组件提供丰富的自定义属性及布局方式,支持横行和纵向布局,使用direction来决定其布局方向,如同普通表单一样,在设置isRequired属性后,表单会显示*符号,用来表示其是否为必填项,但是它与内部校验无关,如果需要让该表单项不为空,请使用规则,同时,组件支持传入校验规则,只要在rules属性中加入不同的规则,即可进行不同的校验,见 表单校验,
比较特殊的是,组件内部使用了焦点吸附,表单项被选中时,会进行对应的焦点操作,对于样式的控制,有几个属性,包括readOnly decoration 在readOnly设置为true时,焦点获取将不会更改样式,而样式的设置,可以使用decoration属性,见FocusDecoration,label设置时,如果是不需要使用label显示,不设置label或labelBuilder即可,其余属性均与布局有关,如crossCenter用于设置label于表单项的交叉轴对其方式,为true时将为居中对齐,否则使用顶部对齐,对于必须指定的项 fieldName,指每一项对应的表单数据
SparkLabelTitle #
SparkLabelTitle为label组件,通常用于选择显示,下拉样式显示等,其样式与flutter的原生组件TitleLabel相似,其提供参数如下
const SparkLabelTitle({
Key? key,
required FormGroupItem manage,
this.suffixIcon,
this.showSuffix,
this.suffixSize,
this.maxLines,
this.onTap,
this.hitText,
this.style,
this.hitTextStyle,
this.padding = EdgeInsets.zero,
this.margin,
this.width,
this.selectDown = false,
this.contentPadding,
}) : super(key: key, manage: manage);
/// custom suffix icon
final Widget? suffixIcon;
/// set show suffix icon
final bool? showSuffix;
/// set suffix icon size
final Size? suffixSize;
/// set text max line count
final int? maxLines;
/// label tap
final SparkLabelTitleData? Function(SparkLabelTitleData data)? onTap;
/// empty hit text
final String? hitText;
/// show text style
final TextStyle? style;
/// hit text style
final TextStyle? hitTextStyle;
/// set body padding
final EdgeInsets padding;
/// set body margin
final EdgeInsets? margin;
final double? width;
/// choose suffix icon type
final bool selectDown;
/// set content and suffix padding
final EdgeInsets? contentPadding;
copied to clipboard
提供包括文字提示、自定义文字内容显示,内部内容更新采用数据回传模式
final SparkLabelTitleData? Function(SparkLabelTitleData data)? onTap;
copied to clipboard
如果在onTap传入的函数中返回 SparkLabelTitleData类型的数据,将会把返回的数据更新到显示区域,并显示对应的内容,完成数据展示
组件包含另一个字段 selectDown 字段用于对尾部默认的箭头图标进行替换,如果值为true将显示向下的箭头 ,也可以设置showSuffix来设置是否显示尾部图标,或者suffixIcon来自定义图标
SparkSelect #
组件为单选组件,用于选择情景,内部参数定义为
const SparkSelect({
Key? key,
required FormGroupItem manage,
required this.options,
this.itemBuilder,
this.itemSpacing,
this.itemSize,
this.selectedDecoration,
this.unSelectedDecoration,
this.alignment,
}) : super(key: key, manage: manage);
/// option data
final List<SparkSelectOption> options;
/// custom item builder
final ItemValueBuilder? itemBuilder;
/// item space
final double? itemSpacing;
/// set up option size
/// use BoxConstraints
final Size? itemSize;
/// set up select option style
final SparkSelectDecoration? selectedDecoration;
/// set up default option style
final SparkSelectDecoration? unSelectedDecoration;
/// option alignment
final WrapAlignment? alignment;
copied to clipboard
对于组件来说,需要指定 options内容,用于显示选择的项,数据类型必须为SparkSelectOption,选中的数据为SparkSelectOption.value,会在表单系统中,自动与外层包裹的SparkFormItem同fieldName字段所对应的属性对应,并更改其值,在进行自定义时itemBuilder将会把内部设置的样式及数据进行传递
/// spark select item options builder
/// [SparkSelect]
typedef ItemValueBuilder = Widget Function(BuildContext context, SparkOption value, SparkSelectDecoration decoration);
copied to clipboard
SparkTagGroup #
标签选择器,器包含多种选择模式,如单选&添加、多选&添加、单选、多选,并可设置是否清除
const SparkTagGroup({
Key? key,
this.itemBuilder,
required FormGroupItem manage,
this.showClean = false,
this.type = SparkTagGroupType.multiple,
this.spacing = 10,
this.runSpacing = 10,
this.onAdd,
this.addWidget,
this.hitText,
this.hitWidget,
this.hitStyle,
this.alignment,
this.cleanIconBuilder,
}) : super(key: key, manage: manage);
/// custom item builder
final TagGroupItemBuilder? itemBuilder;
/// set up clean icon visible
final bool showClean;
/// group type
final SparkTagGroupType type;
/// see [Wrap]
final double spacing;
/// see [Wrap]
final double runSpacing;
/// group out side add function
final SparkTagGroupItem? Function()? onAdd;
/// costom add widget
final Widget? addWidget;
/// empty hit text
final String? hitText;
/// hit widget
final Widget? hitWidget;
/// hit text style
final TextStyle? hitStyle;
/// see [Wrap]
final WrapAlignment? alignment;
/// custom clean icon builder
final TagGroupItemIconBuilder? cleanIconBuilder;
copied to clipboard
组件功能和Select类型,但是对于多标签选择和添加时,显得十分方便,已有的几种模式,已经能满足大部分的场景,只需要对不同的属性进行修改,即可达到对于的效果,特殊的地方在于,onAdd可给外部提供添加能力,或者,你也可以直接操作字段对应的数据,来达到添加的目的
SparkTextField #
基于flutter本身TextField的封装,舍弃了一些原有的功能,对suffix prefix cleanble进行了封装,使用体验更加友好,其余使用与原生功能几乎一致
数据更新 #
表单组件的实现是依据与flutter提供的 InheritedWidget 实现,为了方便更新数据,spark提供了便利的获取和更新方案
SparkBeaconNotification #
0.0.7版本加入
在spark form 系统中,我们提供了一个'信标',使用方式也很简单,只要在SparkFormItem 包裹的范围内获取BuildContext 即可进行数据操作
Builder(builder: (_) {
return GestureDetector(
onTap: () {
List<SparkTagGroupItem> _data = SparkBeaconGetter.form<List<SparkTagGroupItem>>(_, 'select');
_data.add(SparkTagGroupItem.from(name: 'test'));
SparkBeaconNotification(value: _data, field: 'select').dispatch(_);
},
child: const Icon(
Icons.search,
size: 18,
),
);
}),
copied to clipboard
上述代码即为一个简单的更新通知,在范围内,使用该类即可实现数据更新
SparkBeaconGetter.form #
在表单系统中,为了方便获取数据,还提供了一个数据获取方法,在SparkBeaconGetter中,使用静态方法form即可获取到指定的值的值
static T form<T>(BuildContext context, String field) {
...
}
copied to clipboard
值得注意的是,field属性可以指定所有的表单定义属性
表单校验 #
在SparkForm组件中,我们提供了一个SparkFormController,传入实例后,便可对表单进行校验操作
SparkFormController _controller = SparkFormController();
...
SparkForm(
controller: _controller,
manage: _manage,
...
)
...
copied to clipboard
SparkFormController #
在SparkFormController中,提供了多个校验方法
class SparkFormController {
ValidateResult validateField(String fieldName, VerifyType type, {dynamic preValue}) {
...
}
/// validate all rules, get validate result
/// [focusError] auto focus first error
ValidateResult validate({bool? focusError}) {
...
}
/// reset all field data
void resetAll() {
_manage?.reset();
}
}
copied to clipboard
如果你需要检测表单的正确性,只需要调用SparkFormController.validate方法即可,方法提供自动聚焦到第一项错误的功能,SparkFormController.resetAll则会将表单初始化为初始数据,对应的SparkFormController.validateField方法即是对单独的某一个字段进行验证
SparkValidator #
对于表单的验证模块,即对应SparkFormItem中的rules字段,可以对每个属性的值进行验证,对于不同的属性值,验证规则也不同,spark_form内提供多个属性验证器
abstract class SparkValidator {
SparkValidator({
required this.errorMessage,
required this.type,
this.strategy,
});
/// verify error message
String errorMessage;
/// validate type
VerifyType? type;
/// validate strategy
///
FormStrategy? strategy;
/// validate rule
ValidateResult validate(dynamic value, String fieldName, VerifyType? type);
}
copied to clipboard
每个规则可以对应不同的触发校验的方式,设置type即可,如果需要自己的校验器,继承于SparkValidator实现即可
enum VerifyType {
/// verfiy value after changed
change,
/// verfiy value after blur
blur,
/// include change and blur
all,
}
copied to clipboard
然而对于strategy字段,则是对规则的行为做出区分
enum FormStrategy {
/// form change strategy, if valitate error, back to old value
limit,
/// just tip error message
tip,
/// Not to do anything
noop,
}
copied to clipboard
规则设置为FormStrategy.limit时,值将会限制输入,无法变成不符合规则的值,而FormStrategy.tip则会触发表单的提示功能,最后一个属性则是不做任何事,用于区分校验策略
校验规则也各有不同,
SparkLengthValidator
提供一个字符串长度验证器
SparkLengthValidator.length(
this.length, {
required String errorMessage,
required VerifyType? type,
FormStrategy? strategy = FormStrategy.limit,
}) : super(
errorMessage: errorMessage,
type: type,
strategy: strategy,
);
copied to clipboard
可以对属性值的长度进行验证(必须为字符串)
SparkFormatValidator
提供一个正则验证器
SparkFormatValidator.form(
this.rule, {
required String errorMessage,
required VerifyType? type,
FormStrategy? strategy = FormStrategy.limit,
}) : super(
errorMessage: errorMessage,
type: type,
strategy: strategy,
);
copied to clipboard
可对属性值的格式进行验证(必须为字符串)
SparkNumberValidator
提供一个数字格式验证器,包含多种验证方式,包括字符格式正确性验证、大小范围验证、整数和小数长度验证,通过不同具名构造函数构建即可使用
后者的验证建立在数字格式的基础上进行,如果需要更加准确的提示,应该先使用number验证字符格式
/// number only
SparkNumberValidator.number({
required String errorMessage,
required VerifyType? type,
FormStrategy? strategy = FormStrategy.limit,
}) : super(
errorMessage: errorMessage,
type: type,
strategy: strategy,
);
/// setup number range
SparkNumberValidator.range({
required this.max,
required this.min,
required String errorMessage,
required VerifyType? type,
FormStrategy? strategy = FormStrategy.limit,
}) : assert(
max > min,
'SparkNumberValidator.range max must be max than min',
),
super(
errorMessage: errorMessage,
type: type,
strategy: strategy,
);
/// setup number integer part length and decimal part length
SparkNumberValidator.length({
required this.integerLength,
required this.decimalLength,
required String errorMessage,
required VerifyType? type,
FormStrategy? strategy = FormStrategy.limit,
}) : super(
errorMessage: errorMessage,
type: type,
strategy: strategy,
);
copied to clipboard
对于校验值,也只能为字符串
SparkRequiredValidator
提供一个非空验证器
SparkRequiredValidator.required({
required String errorMessage,
required VerifyType? type,
FormStrategy? strategy = FormStrategy.limit,
}) : super(
errorMessage: errorMessage,
type: type,
strategy: strategy,
);
copied to clipboard
兼容已有数据结构
主题 #
对于spark_form来说。大部分情况下都可以通过组件上的自定义属性来更改不同的样式,但是有没有一种一劳永逸的方式来更改同表单内的样式呢?答案的存在的
在spark_form中存在一个组件SparkThemeData,其实现类似于flutter的ThemeData实现
class SparkThemeData extends InheritedWidget {
/// form theme data manage provider
const SparkThemeData({required Widget child, required this.theme, Key? key})
: super(child: child, key: key);
/// form theme
final SparkTheme theme;
/// get form theme data of context
static SparkTheme? of(BuildContext context) {
return context.dependOnInheritedWidgetOfExactType<SparkThemeData>()?.theme;
}
@override
bool updateShouldNotify(covariant InheritedWidget oldWidget) {
return true;
}
}
copied to clipboard
通过继承InheritedWidget实现一个数据共享中心,其包裹的组件都可以通过SparkThemeData.of获取其内部存储的theme,基于flutter提供的特性,我们实现了一套主题系统,你可以通过设置主题的方式,来初始化全局的表单样式,只需要将表单组件作为SparkThemeData的字组件即可,例如
SparkThemeData(child: SparkForm(
controller: _controller,
manage: _manage,
child: ...
), theme: SparkTheme(),)
copied to clipboard
即可对一系列的样式进行初始化定义,方便统一的风格和主题的定制,SparkTheme目前支持的属性为
const SparkTheme({
this.labelColor = _defaultFontColor,
this.hitColor = _hitTextColor,
this.labelFontSize = _defaultFormItemFontSize,
this.labelFontWeight = FontWeight.w500,
this.requiredColor = _errorOrRequiredColor,
this.requiredPrefix = '*',
this.formItemFontSize = _defaultFormItemFontSize,
this.formItemColor = _defaultFormItemColor,
this.formItemDisabledColor = _defaultFormItemDisabledColor,
this.lableWidth = _defaultLabelWidth,
this.lablePadding = EdgeInsets.zero,
this.formItemDecoration = _defaultFormDecoration,
this.formItemPadding = _defaultFormItemPadding,
this.formItemMargin = _defaultFormItemMargin,
this.selectItemSize = _defaultSelectItemSize,
this.selectedItemDecoration = _defaultSelectedDecoration,
this.unSelectedItemDecoration = _defaultUnSelectedDecoration,
this.errorColor = _errorOrRequiredColor,
this.tagItemDecoration = _defaultTagDecoration,
this.tagSelectedItemDecoration = _defaultTagSelectedDecoration,
this.tagStyle = _defaultTagItemStyle,
this.tagSelectedStyle = _defaultSelectedItemStyle,
this.tagMinWidth = _defaultTagWidth,
this.tagAddDecoration = _defaultTagAddDecoration,
this.tagContentPadding = _defaultTagContentPadding,
});
copied to clipboard
主题和组件本身的样式并不冲突,如果组件内部设置了对应样式,将不会使用主题样式
目前主题功能还处于深度定制阶段,一些属性还未列为主题管理
焦点吸附组件 #
在spark_form中,提供了一个焦点吸附组件 FocusPointerScope,其实现是基于flutter的焦点管理体系的,在进行表单选择切换时,会自动进行焦点的获取,对于其内部实现为独立封装,可用于其他功能的实现,内部吸附的组件为一个Container可对焦点的响应做出各种行为,并暴露相应的事件
class FocusPointerScope extends StatefulWidget {
const FocusPointerScope({
Key? key,
this.focusNode,
required this.child,
this.shadow = false,
this.enabled,
this.decoration,
this.padding,
this.margin,
this.alignment,
this.constraints,
this.onTap,
this.onFocus,
this.onUnFocus,
this.width,
this.height,
}) : super(key: key);
final FocusNode? focusNode;
final Widget child;
/// only request focus,but not set focus style
final bool? shadow;
/// focus enable
final bool? enabled;
/// widget decoration
final FocusDecoration? decoration;
/// content padding
final EdgeInsets? padding;
/// content margin
final EdgeInsets? margin;
final AlignmentGeometry? alignment;
final BoxConstraints? constraints;
/// on widget tap
final VoidCallback? onTap;
/// on focus
final VoidCallback? onFocus;
/// on lose focus
final VoidCallback? onUnFocus;
final double? width;
final double? height;
@override
State<StatefulWidget> createState() => _FocusPointerScopeBase();
}
copied to clipboard
其实现原理的:通过Listener进行事件监听,得到内部点击事件,然后进行焦点的获取
_handleTap() {
...
FocusScope.of(context).requestFocus(_effectiveFocusNode);
}
@override
void initState() {
_effectiveFocusNode.addListener(_handleFocusChanged);
// attach focusNode target widget
_focusAttachment = _effectiveFocusNode.attach(context);
super.initState();
}
@override
void didUpdateWidget(covariant FocusPointerScope oldWidget) {
super.didUpdateWidget(oldWidget);
if (widget.focusNode != oldWidget.focusNode) {
(oldWidget.focusNode ?? _focusNode)?.removeListener(_handleFocusChanged);
(widget.focusNode ?? _focusNode)?.addListener(_handleFocusChanged);
// replace focusNode, rebind context
_focusAttachment?.detach();
_focusAttachment = _effectiveFocusNode.attach(context);
}
_effectiveFocusNode.canRequestFocus = _canRequestFocus;
}
@override
void dispose() {
_effectiveFocusNode.removeListener(_handleFocusChanged);
_focusNode?.dispose();
_focusAttachment?.detach();
super.dispose();
}
copied to clipboard
由此可以得到一个焦点管理的实现,避免了焦点混乱
自定义表单组件 #
对于自定义表单组件,我们提供了两种封装思路
组件形式封装 #
基于组件的形式进行封装的话,组件应该对应以下类进行对应的继承实现
abstract class SparkFormStateLessWidget<D> extends StatelessWidget {
const SparkFormStateLessWidget({Key? key, required this.manage}) : super(key: key);
final FormGroupItem manage;
D get fieldData => manage.notifier.data;
void handleFormDataChange(BuildContext context, dynamic newValue) {
FormDataChangeNotification(
newValue: newValue,
).dispatch(context);
}
}
abstract class SparkFormWidget extends StatefulWidget {
const SparkFormWidget({Key? key, required this.manage}) : super(key: key);
final FormGroupItem manage;
}
abstract class SparkFormWidgetBase<T extends SparkFormWidget, D> extends State<T> {
D get fieldData => widget.manage.notifier.data;
FormGroupItem get manage => widget.manage;
void handleFormDataChange(dynamic newValue) {
FormDataChangeNotification(
newValue: newValue,
).dispatch(context);
}
@override
void initState() {
widget.manage.notifier.addListener(valueChangeNotify);
super.initState();
}
void valueChangeNotify();
@override
void dispose(){
widget.manage.notifier.removeListener(valueChangeNotify);
super.dispose();
}
}
copied to clipboard
分别对应有状态组件和无状态组件的继承实现,基类中存在方法handleFormDataChange,只需要将组件产生的新值通过此方法进行传递,form就可以处理到对应的项,然后在 valueChangeNotify进行回调执行,也就是校验完成后会执行此方法,可用于组件的刷新和其他处理
组件包裹 #
如果不需要使用到组件形式的实现,可以使用SparkWrapper来进行组件的包裹,但是需要注意的是,该形式无法触发表单的验证功能,仅仅提供表单内部值发生变化时的更新功能,实现方式是基于数据监听的方法实现
const SparkWrapper({
Key? key,
required this.builder,
required FormGroupItem manage,
}) : super(key: key, manage: manage);
copied to clipboard
只需要将你自己的组件包裹在其中,即可得到更新值和自定刷新的能力,缺点是不存在组件缓存,不建议消耗过大的组件使用此方法进行处理
自定义ModalSheet #
在组件内部,实现了一个基于Navigator的 modalSheet,相对于flutter提供的showModalBottomSheet来说,去除了布局的最大高度约束,元素大小及位置布局相对自由
Future<T?> showSparkModalSheet<T>({
required BuildContext context,
required WidgetBuilder builder,
ShapeBorder? shape,
bool useRootNavigator = false,
Clip? clipBehavior,
}) {
final NavigatorState navigator =
Navigator.of(context, rootNavigator: useRootNavigator);
return navigator.push(_SparkModalRoute<T>(
builder: builder,
shape: shape,
clipBehavior: clipBehavior,
barrierLabel: MaterialLocalizations.of(context).modalBarrierDismissLabel,
));
}
copied to clipboard
调用showSparkModalSheet方法即可创建一个路由弹出框,内部视图可自定义实现,但是值得注意的是,内部元素必须有自身的高度,对于约束模型来说,如果内部元素没有大小约束,将会占满整个试图,即最大高宽,如果需要pop掉视图,应该使用builder给定的context来操作,如
Navigator.of(dialogContext).pop();
copied to clipboard
即可让modalSheet消失
自定义3D滚轮选择器 #
组件是基于CupertinoPicker进行封装,对于滚轮的各个阶段事件进行分发
class SparkCommonPicker extends StatelessWidget {
const SparkCommonPicker({
Key? key,
required this.controller,
required this.itemHeight,
required this.itemBuilder,
required this.itemCount,
this.onChanged,
this.onChange,
this.onStart,
this.selectionOverlay,
}) : super(key: key);
/// picker controller
final FixedExtentScrollController controller;
/// single option height
final double itemHeight;
/// pick option builder
final SparkPickerBuilder itemBuilder;
/// item count
final int itemCount;
/// on changed, get last result
final SparkPickerChanged? onChanged;
/// scroll animation change index, get scrolling index value
final SparkPickerChanged? onChange;
final Function? onStart;
/// selection overlay widget
final Widget? selectionOverlay;
}
copied to clipboard
组件SparkCommonPicker是一个单独的存在,也就是说,如果你需要使用一个弹出选择框,你需要将
showSparkModalSheet与其组合使用,即可成为一个简单的选择组件
SparkPicker #
组件是基于SparkCommonPicker的封装,可以直接用于使用
class SparkPicker<T> extends StatelessWidget {
const SparkPicker({
required this.options,
this.itemHeight = 40,
this.itemBuilder,
this.style,
this.controller,
Key? key,
}) : super(key: key)
copied to clipboard
showSparkMultiplePicker #
spark内部提供了一个多列滑动选择器,选择器内部可以进行多列数据的选择
Future<Map<String, T>?> showSparkMultiplePicker<T>({
required BuildContext context,
required Map<String, List<SparkPickerData<T>>> options,
double itemHeight = 40,
SparkPickerBuilder? itemBuilder,
bool showBar = true,
String cancelText = '取消',
String confirmText = '确定',
TextStyle? cancelStyle,
TextStyle? confirmStyle,
double height = 300,
SparkPickerTitleBarBuilder? barBuilder,
Map<String, T>? defaultValue,
})
copied to clipboard
对于选择器来说,options字段需要设置指定的key,在最后返回的数据中,会返回对应的数据字段的Map集合,同样,对于defaultValue也是需要对于的,如果有其他非必需属性,会被忽略,不会进行使用
showSparkSingePicker #
单选选择器是一个基于showSparkMultiplePicker的封装,内部对数据格式进行了一个转换,只需要传入单个数据集合即可进行选择操作
Future<T?> showSparkSingePicker<T>({
required BuildContext context,
required List<SparkPickerData<T>> options,
double itemHeight = 40,
SparkPickerBuilder? itemBuilder,
bool showBar = true,
String cancelText = '取消',
String confirmText = '确定',
TextStyle? cancelStyle,
TextStyle? confirmStyle,
double height = 300,
SparkPickerTitleBarBuilder? barBuilder,
T? defaultValue,
})
copied to clipboard
使用方式和 showSparkMultiplePicker基本一致,参数也基本一致
时间日期选择器 #
时间日期选择器SparkDatePicker提供了很多非常强大的功能,组件可单独使用,如果需要进行弹出选择,可以使用提供的函数
Future<T?> showSparkDatePicker<T>({
required BuildContext context,
double height = 260,
DateTime? defaultDate,
DateTime? maxDate,
DateTime? minDate,
double itemHeight = 40,
DatePickerTheme theme = _defaultDatePickerTheme,
DatePickerBehavior behavior = DatePickerBehavior.confirm,
/// [SparkDateFormat] format
String? format,
ShapeBorder shape = _defaultPickerShape,
}) {
assert(T == String || T == DateTime, 'date picker must setup return type');
return showSparkModalSheet<T>(
context: context,
shape: shape,
builder: (_) => SparkDatePicker<T>(
defaultDate: defaultDate,
height: height,
theme: theme,
minDate: minDate,
maxDate: maxDate,
itemHeight: itemHeight,
behavior: behavior,
format: format ?? SparkDateFormat.yearMonthDayAndHourMinuteSecond,
onChanged: (_value) {
Navigator.of(_).pop(_value);
},
),
);
}
copied to clipboard
对于函数showSparkDatePicker来说,需要制定泛型T的类型,目前支持的类型为String DateTime,这将作为时间选择器的内部数据返回格式类型,函数的返回结果和泛型类型一致,对于参数来说,可以指定默认的时间日期和最大最小日期
/// default date
final DateTime? defaultDate;
/// min date
final DateTime? minDate;
/// max date
final DateTime? maxDate;
copied to clipboard
设置参数后只能在固定范围内选择,否则生成的选择范围为[20 <- now -> 30],选择器还提供了一个更加方便的功能,更具时间格式来选择对应的时间或日期字段,然后返回对应的结构(String模式下),对应的为设置 format字段,其值为
class SparkDateFormat {
/// use part:
/// 'yyyy' year
/// 'MM' month
/// 'dd' day
/// 'hh' hour
/// 'mm' minute
/// 'ss' second
SparkDateFormat._();
static const String _yearPart = 'yyyy';
static const String _monthPart = 'MM';
static const String _dayPart = 'dd';
static const String _hourPart = 'hh';
static const String _minutePart = 'mm';
static const String _secondPart = 'ss';
/// date format as '2020-01'
static const String yearMonth = 'yyyy-MM';
/// date format as '2020/01'
static const String yearMonthObliqueLine = 'yyyy/MM';
/// date format as '2020-01-01'
static const String yearMonthDay = 'yyyy-MM-dd';
/// date format as '2020/01/01'
static const String yearMonthDayObliqueLine = 'yyyy/MM/dd';
/// time format as '12:01'
static const String hourMinute = 'hh:mm';
/// time format as '12:01:59'
static const String hourMinuteSecond = 'hh:mm:ss';
/// date time format as '2021-12-01 12:01'
static const String yearMonthDayAndHourMinute = 'yyyy-MM-dd hh:mm';
/// date time format as '2021/12/01 12:01'
static const String yearMonthDayObliqueLineAndHourMinute = 'yyyy/MM/dd hh:mm';
/// date time format as '2021-12-01 12:01:59'
static const String yearMonthDayAndHourMinuteSecond = 'yyyy-MM-dd hh:mm:ss';
/// date time format as '2021/12/01 12:01:59'
static const String yearMonthDayObliqueLineAndHourMinuteSecond =
'yyyy/MM/dd hh:mm:ss';
}
copied to clipboard
其中_XXXPart为解析合法字段,合法分隔符为/ : 三种,对应的格式对应显示对应的选择列
不建议使用自定义的排列方式,因为这可能让其功能出现异常
For personal and professional use. You cannot resell or redistribute these repositories in their original state.
There are no reviews.