flutter_flow_choice_chips.dart 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. import 'form_field_controller.dart';
  2. import 'package:flutter/foundation.dart';
  3. import 'package:flutter/material.dart';
  4. import 'package:flutter/scheduler.dart';
  5. import 'package:font_awesome_flutter/font_awesome_flutter.dart';
  6. import '/flutter_flow/flutter_flow_util.dart';
  7. class ChipData {
  8. const ChipData(this.label, [this.iconData]);
  9. final String label;
  10. final IconData? iconData;
  11. }
  12. class ChipStyle {
  13. const ChipStyle({
  14. this.backgroundColor,
  15. this.textStyle,
  16. this.iconColor,
  17. this.iconSize,
  18. this.labelPadding,
  19. this.elevation,
  20. this.borderColor,
  21. this.borderWidth,
  22. this.borderRadius,
  23. });
  24. final Color? backgroundColor;
  25. final TextStyle? textStyle;
  26. final Color? iconColor;
  27. final double? iconSize;
  28. final EdgeInsetsGeometry? labelPadding;
  29. final double? elevation;
  30. final Color? borderColor;
  31. final double? borderWidth;
  32. final BorderRadius? borderRadius;
  33. }
  34. class FlutterFlowChoiceChips extends StatefulWidget {
  35. const FlutterFlowChoiceChips({
  36. super.key,
  37. required this.options,
  38. required this.onChanged,
  39. required this.controller,
  40. required this.selectedChipStyle,
  41. required this.unselectedChipStyle,
  42. required this.chipSpacing,
  43. this.rowSpacing = 0.0,
  44. required this.multiselect,
  45. this.initialized = true,
  46. this.alignment = WrapAlignment.start,
  47. this.disabledColor,
  48. this.wrapped = true,
  49. });
  50. final List<ChipData> options;
  51. final void Function(List<String>?)? onChanged;
  52. final FormFieldController<List<String>> controller;
  53. final ChipStyle selectedChipStyle;
  54. final ChipStyle unselectedChipStyle;
  55. final double chipSpacing;
  56. final double rowSpacing;
  57. final bool multiselect;
  58. final bool initialized;
  59. final WrapAlignment alignment;
  60. final Color? disabledColor;
  61. final bool wrapped;
  62. @override
  63. State<FlutterFlowChoiceChips> createState() => _FlutterFlowChoiceChipsState();
  64. }
  65. class _FlutterFlowChoiceChipsState extends State<FlutterFlowChoiceChips> {
  66. late List<String> choiceChipValues;
  67. List<String> get selectedValues => widget.controller.value ?? [];
  68. @override
  69. void initState() {
  70. super.initState();
  71. choiceChipValues = List.from(selectedValues);
  72. if (!widget.initialized && choiceChipValues.isNotEmpty) {
  73. SchedulerBinding.instance.addPostFrameCallback(
  74. (_) {
  75. if (widget.onChanged != null) {
  76. widget.onChanged!(choiceChipValues);
  77. }
  78. },
  79. );
  80. }
  81. }
  82. @override
  83. void dispose() {
  84. super.dispose();
  85. }
  86. @override
  87. Widget build(BuildContext context) {
  88. final children = widget.options.map<Widget>(
  89. (option) {
  90. final selected = selectedValues.contains(option.label);
  91. final style =
  92. selected ? widget.selectedChipStyle : widget.unselectedChipStyle;
  93. return Theme(
  94. data: Theme.of(context).copyWith(canvasColor: Colors.transparent),
  95. child: ChoiceChip(
  96. selected: selected,
  97. onSelected: widget.onChanged != null
  98. ? (isSelected) {
  99. choiceChipValues = List.from(selectedValues);
  100. if (isSelected) {
  101. widget.multiselect
  102. ? choiceChipValues.add(option.label)
  103. : choiceChipValues = [option.label];
  104. widget.controller.value = List.from(choiceChipValues);
  105. setState(() {});
  106. } else {
  107. if (widget.multiselect) {
  108. choiceChipValues.remove(option.label);
  109. widget.controller.value = List.from(choiceChipValues);
  110. setState(() {});
  111. }
  112. }
  113. widget.onChanged!(choiceChipValues);
  114. }
  115. : null,
  116. label: Text(
  117. option.label,
  118. style: style.textStyle,
  119. overflow: TextOverflow.ellipsis,
  120. ),
  121. labelPadding: style.labelPadding,
  122. avatar: option.iconData != null
  123. ? FaIcon(
  124. option.iconData,
  125. size: style.iconSize,
  126. color: style.iconColor,
  127. )
  128. : null,
  129. elevation: style.elevation,
  130. disabledColor: widget.disabledColor,
  131. selectedColor:
  132. selected ? widget.selectedChipStyle.backgroundColor : null,
  133. backgroundColor:
  134. selected ? null : widget.unselectedChipStyle.backgroundColor,
  135. shape: RoundedRectangleBorder(
  136. borderRadius: style.borderRadius ?? BorderRadius.circular(16),
  137. side: BorderSide(
  138. color: style.borderColor ?? Colors.transparent,
  139. width: style.borderWidth ?? 0,
  140. ),
  141. ),
  142. materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
  143. ),
  144. );
  145. },
  146. ).toList();
  147. if (widget.wrapped) {
  148. return Wrap(
  149. spacing: widget.chipSpacing,
  150. runSpacing: widget.rowSpacing,
  151. alignment: widget.alignment,
  152. crossAxisAlignment: WrapCrossAlignment.center,
  153. children: children,
  154. );
  155. } else {
  156. return SingleChildScrollView(
  157. scrollDirection: Axis.horizontal,
  158. clipBehavior: Clip.none,
  159. child: Row(
  160. crossAxisAlignment: CrossAxisAlignment.center,
  161. children: children.divide(
  162. SizedBox(width: widget.chipSpacing),
  163. ),
  164. ),
  165. );
  166. }
  167. }
  168. }