group.dart 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. import 'package:flutter/material.dart';
  2. import 'package:get/get.dart';
  3. import 'cell.dart';
  4. typedef VRadioCellGroupItemBuilder<T> = Widget Function(T data);
  5. typedef VRadioCellGroupCheckChanged<T, TValue> = void Function(
  6. TValue value,
  7. bool isChecked,
  8. T data,
  9. TValue? checkedValue,
  10. );
  11. class RadioCellGroupItem<T> {
  12. final T data;
  13. final bool isChecked;
  14. final bool isDisabled;
  15. RadioCellGroupItem(
  16. this.data, {
  17. this.isChecked = false,
  18. this.isDisabled = false,
  19. });
  20. }
  21. class VRadioCellGroup<T, TValue> extends StatefulWidget {
  22. final List<RadioCellGroupItem<T>> source;
  23. /// 选项文本提取函数
  24. final String Function(T data) labelGetter;
  25. /// 选项值提取函数
  26. final TValue Function(T data) valueGetter;
  27. final VRadioCellGroupCheckChanged<T, TValue>? onChanged;
  28. final bool isScrollable;
  29. final ScrollController? controller;
  30. const VRadioCellGroup({
  31. super.key,
  32. required this.source,
  33. required this.labelGetter,
  34. required this.valueGetter,
  35. this.onChanged,
  36. this.isScrollable = true,
  37. this.controller,
  38. });
  39. @override
  40. State<StatefulWidget> createState() => _VRadioCellGroupState<T, TValue>();
  41. }
  42. class _VRadioCellGroupState<T, TValue>
  43. extends State<VRadioCellGroup<T, TValue>> {
  44. TValue? _checkedValue;
  45. @override
  46. void initState() {
  47. T? data = widget.source.firstWhereOrNull((e) => e.isChecked)?.data;
  48. if (data != null) {
  49. _checkedValue = widget.valueGetter.call(data);
  50. }
  51. super.initState();
  52. }
  53. @override
  54. Widget build(BuildContext context) {
  55. final divider = Divider(
  56. thickness: 1,
  57. color: Colors.grey.shade300,
  58. height: 2,
  59. );
  60. final children = <Widget>[];
  61. final count = widget.source.length;
  62. for (var i = 0; i < count; i++) {
  63. if (i > 0) {
  64. children.add(divider);
  65. }
  66. final item = widget.source[i];
  67. children.add(_buildItemWidget(item));
  68. }
  69. if (widget.isScrollable) {
  70. return ListView(
  71. shrinkWrap: true,
  72. controller: widget.controller ?? ScrollController(),
  73. children: children,
  74. );
  75. } else {
  76. return Column(
  77. mainAxisAlignment: MainAxisAlignment.center,
  78. mainAxisSize: MainAxisSize.min,
  79. children: children,
  80. );
  81. }
  82. }
  83. Widget _buildItemWidget(RadioCellGroupItem<T> item) {
  84. final label = widget.labelGetter.call(item.data);
  85. final value = widget.valueGetter.call(item.data);
  86. final isChecked = _checkedValue == value;
  87. return VRadioCell<TValue>(
  88. label: label,
  89. value: value,
  90. isChecked: isChecked,
  91. isDisabled: item.isDisabled,
  92. onChanged: (_, isChecked) {
  93. _onCheckChanged(value, item.data, isChecked);
  94. },
  95. );
  96. }
  97. void _onCheckChanged(TValue value, T data, bool isChecked) {
  98. setState(() {
  99. if (isChecked) {
  100. _checkedValue = value;
  101. } else {
  102. _checkedValue = null;
  103. }
  104. widget.onChanged?.call(value, isChecked, data, _checkedValue);
  105. });
  106. }
  107. }