infinity_picker_field.dart 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. /*
  2. * @Author: XianKaiQun
  3. * @Date: 2020-08-25 14:59:08
  4. * @LastEditors : WuWei
  5. * @LastEditTime : 2023-05-23 11:40:04
  6. * @Description:
  7. */
  8. import 'package:flutter/material.dart';
  9. import 'package:flutter/services.dart';
  10. import 'package:wisdom_cli/wisdom_cli.dart';
  11. ///[value]当前的每一层级已选中的项组成的[List],
  12. ///[trigger] 触发弹出弹层的函数。
  13. typedef WInfinityPickerFieldBuilder<T> = Widget Function(
  14. List<T> value,
  15. Future<void> Function() trigger,
  16. );
  17. typedef WInfinityPickerFieldOnChanged<T> = void Function(List<T>? value);
  18. ///无限单选
  19. ///
  20. ///在此高阶组件中已实现调用[WPickerUtil.infinity]与[Widget]间的调用,
  21. ///
  22. ///所以你只需要关注[builder]输出的什么Widget即可。
  23. ///
  24. ///
  25. class WInfinityPickerField<T extends WPickerEntity> extends StatefulWidget {
  26. WInfinityPickerField({
  27. Key? key,
  28. required this.getData,
  29. required this.isLast,
  30. required this.builder,
  31. this.title,
  32. this.value,
  33. this.onChanged,
  34. }) : super(key: key);
  35. final Future<bool> Function(List<T>) isLast;
  36. final WInfinityPickerFieldBuilder<T> builder;
  37. final Widget? title;
  38. ///[getData]
  39. ///
  40. ///[selects]是每一个层级中已选择的项组成的[List],
  41. ///[selects]可能是[null],也可能[List.length==0],
  42. ///所以一定要正确的将[selects]作为条件,并输出正确的[List<T>]。
  43. final Future<List<T>> Function(List<T> item) getData;
  44. ///初始化每一个层级中已选的项组成的[List]。
  45. final List<T>? value;
  46. final WInfinityPickerFieldOnChanged<T>? onChanged;
  47. @override
  48. _WInfinityPickerFieldState<T> createState() =>
  49. _WInfinityPickerFieldState<T>();
  50. }
  51. class _WInfinityPickerFieldState<T extends WPickerEntity>
  52. extends State<WInfinityPickerField<T>> {
  53. List<T>? _value;
  54. List<T> get value => _value ?? [];
  55. @override
  56. void initState() {
  57. super.initState();
  58. _value = widget.value;
  59. }
  60. ///触发单选弹出层
  61. Future<void> _trigger() async {
  62. final res = await WPickerUtil.infinity<T>(
  63. context,
  64. title: widget.title,
  65. getData: widget.getData,
  66. initialValue: _value ?? [],
  67. isLast: widget.isLast,
  68. );
  69. if (res != null) {
  70. _onChanged(res);
  71. }
  72. }
  73. ///触发[widget.onChanged],
  74. ///刷新视图[widget.builder]
  75. void _onChanged(List<T>? value) {
  76. if (_value == value) return;
  77. _value = value!;
  78. setState(() {});
  79. if (widget.onChanged != null) {
  80. widget.onChanged!(value);
  81. }
  82. }
  83. @override
  84. Widget build(BuildContext context) {
  85. return widget.builder(value, () => _trigger());
  86. }
  87. }
  88. ///无限单选--表单项。
  89. ///
  90. ///基于[WInfinityPickerField],和[WFormField]。
  91. ///
  92. ///[WInfinityPickerFormField.textField],
  93. ///使用[TextField]替代了[WInfinityPickerField.builder]方法
  94. ///
  95. class WInfinityPickerFormField<T extends WPickerEntity>
  96. extends WFormField<List<T>> {
  97. WInfinityPickerFormField({
  98. Key? key,
  99. required WInfinityPickerFieldBuilder<T> builder,
  100. required Future<List<T>> Function(List<T> item) getData,
  101. required Future<bool> Function(List<T>) isLast,
  102. required this.field,
  103. Widget? title,
  104. this.onChanged,
  105. FormFieldSetter<List<T>>? onSaved,
  106. FormFieldValidator<List<T>>? validator,
  107. AutovalidateMode autovalidateMode = AutovalidateMode.disabled,
  108. bool enabled = true,
  109. }) : super(
  110. key: key,
  111. field: field,
  112. onSaved: onSaved,
  113. validator: validator,
  114. autovalidateMode: autovalidateMode,
  115. enabled: enabled,
  116. builder: (WFormFieldState<List<T>> fieldState) {
  117. final state = fieldState as _WInfinityPickerFormFieldState<T>;
  118. return WInfinityPickerField(
  119. title: title,
  120. isLast: isLast,
  121. value: state.value,
  122. getData: getData,
  123. builder: builder,
  124. onChanged: (value) => state.didChange(value as List<T>?),
  125. );
  126. },
  127. );
  128. ///直接使用[textField]进行builder
  129. WInfinityPickerFormField.textField({
  130. Key? key,
  131. required String Function(List<T> value) buildName,
  132. required Future<List<T>> Function(List<T> item) getData,
  133. required Future<bool> Function(List<T>) isLast,
  134. required this.field,
  135. Widget? title,
  136. this.onChanged,
  137. TextEditingController? controller,
  138. FormFieldSetter<List<T>>? onSaved,
  139. FormFieldValidator<List<T>>? validator,
  140. AutovalidateMode autovalidateMode = AutovalidateMode.disabled,
  141. bool enabled = true,
  142. FocusNode? focusNode,
  143. InputDecoration? decoration,
  144. TextInputType? keyboardType,
  145. TextCapitalization textCapitalization = TextCapitalization.none,
  146. TextInputAction? textInputAction,
  147. TextStyle? style,
  148. StrutStyle? strutStyle,
  149. TextDirection? textDirection,
  150. TextAlign textAlign = TextAlign.start,
  151. TextAlignVertical? textAlignVertical,
  152. bool autofocus = false,
  153. // bool readOnly = false,
  154. ToolbarOptions? toolbarOptions,
  155. bool? showCursor,
  156. String obscuringCharacter = '•',
  157. bool obscureText = false,
  158. bool autocorrect = true,
  159. SmartDashesType? smartDashesType,
  160. SmartQuotesType? smartQuotesType,
  161. bool enableSuggestions = true,
  162. MaxLengthEnforcement maxLengthEnforcement = MaxLengthEnforcement.enforced,
  163. int maxLines = 1,
  164. int? minLines,
  165. bool expands = false,
  166. int? maxLength,
  167. // GestureTapCallback onTap,
  168. VoidCallback? onEditingComplete,
  169. ValueChanged<String>? onFieldSubmitted,
  170. List<TextInputFormatter>? inputFormatters,
  171. double cursorWidth = 2.0,
  172. Radius? cursorRadius,
  173. Color? cursorColor,
  174. Brightness? keyboardAppearance,
  175. EdgeInsets scrollPadding = const EdgeInsets.all(20.0),
  176. bool enableInteractiveSelection = true,
  177. InputCounterWidgetBuilder? buildCounter,
  178. ScrollPhysics? scrollPhysics,
  179. Iterable<String>? autofillHints,
  180. }) :
  181. super(
  182. key: key,
  183. field: field,
  184. onSaved: onSaved,
  185. validator: validator,
  186. autovalidateMode: autovalidateMode,
  187. enabled: enabled,
  188. builder: (WFormFieldState<List<T>> fieldState) {
  189. final state = fieldState as _WInfinityPickerFormFieldState<T>;
  190. //主题
  191. InputDecoration _decoration = decoration ?? InputDecoration();
  192. _decoration = _decoration.applyDefaults(
  193. Theme.of(state.context).inputDecorationTheme,
  194. );
  195. _decoration = _decoration.copyWith(
  196. suffixIconConstraints:
  197. _decoration.suffixIconConstraints ?? const BoxConstraints(),
  198. suffixIcon: _decoration.suffixIcon ??
  199. Icon(
  200. Icons.chevron_right,
  201. color: Colors.black38,
  202. ),
  203. errorText: state.errorText,
  204. );
  205. final _controller = controller ?? TextEditingController();
  206. _controller.value = _controller.value.copyWith(
  207. text: buildName(state.value ?? []),
  208. );
  209. return WInfinityPickerField(
  210. title: title,
  211. isLast: isLast,
  212. value: state.value,
  213. getData: getData,
  214. onChanged: (value) => state.didChange(value as List<T>?),
  215. builder: (value, trigger) {
  216. return TextField(
  217. controller: _controller,
  218. focusNode: focusNode,
  219. decoration: _decoration,
  220. keyboardType: keyboardType,
  221. textInputAction: textInputAction,
  222. style: style,
  223. strutStyle: strutStyle,
  224. textAlign: textAlign,
  225. textAlignVertical: textAlignVertical,
  226. textDirection: textDirection,
  227. textCapitalization: textCapitalization,
  228. autofocus: autofocus,
  229. toolbarOptions: toolbarOptions,
  230. readOnly: true,
  231. showCursor: showCursor,
  232. obscuringCharacter: obscuringCharacter,
  233. obscureText: obscureText,
  234. autocorrect: autocorrect,
  235. smartDashesType: smartDashesType ??
  236. (obscureText
  237. ? SmartDashesType.disabled
  238. : SmartDashesType.enabled),
  239. smartQuotesType: smartQuotesType ??
  240. (obscureText
  241. ? SmartQuotesType.disabled
  242. : SmartQuotesType.enabled),
  243. enableSuggestions: enableSuggestions,
  244. maxLengthEnforcement: maxLengthEnforcement,
  245. maxLines: maxLines,
  246. minLines: minLines,
  247. expands: expands,
  248. maxLength: maxLength,
  249. // onChanged: onChangedHandler,
  250. onTap: () => trigger(),
  251. onEditingComplete: onEditingComplete,
  252. onSubmitted: onFieldSubmitted,
  253. inputFormatters: inputFormatters,
  254. enabled: enabled,
  255. cursorWidth: cursorWidth,
  256. cursorRadius: cursorRadius,
  257. cursorColor: cursorColor,
  258. scrollPadding: scrollPadding,
  259. scrollPhysics: scrollPhysics,
  260. keyboardAppearance: keyboardAppearance,
  261. enableInteractiveSelection: enableInteractiveSelection,
  262. buildCounter: buildCounter,
  263. autofillHints: autofillHints,
  264. );
  265. },
  266. );
  267. },
  268. );
  269. final String field;
  270. final WInfinityPickerFieldOnChanged<T>? onChanged;
  271. @override
  272. _WInfinityPickerFormFieldState<T> createState() =>
  273. _WInfinityPickerFormFieldState<T>();
  274. }
  275. class _WInfinityPickerFormFieldState<T extends WPickerEntity>
  276. extends WFormFieldState<List<T>> {
  277. @override
  278. WInfinityPickerFormField<T> get widget =>
  279. super.widget as WInfinityPickerFormField<T>;
  280. @override
  281. void didChange(List<T>? value) {
  282. super.didChange(value);
  283. if (widget.onChanged != null) {
  284. widget.onChanged!(value);
  285. }
  286. }
  287. }