selectBox_button.dart 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. import 'package:flutter/material.dart';
  2. ///按钮式单选框组
  3. class VSelectBoxButtonGroup<T, TValue> extends StatefulWidget {
  4. final List<T> source;
  5. final TValue? value;
  6. final String Function(T data) labelGetter;
  7. final TValue Function(T data) valueGetter;
  8. final ValueChanged<TValue?>? onChanged;
  9. final double? itemWidth;
  10. const VSelectBoxButtonGroup({
  11. super.key,
  12. required this.source,
  13. this.value,
  14. required this.labelGetter,
  15. required this.valueGetter,
  16. this.onChanged,
  17. this.itemWidth,
  18. });
  19. @override
  20. State<StatefulWidget> createState() => _VSelectBoxGroupState<T, TValue>();
  21. }
  22. class _VSelectBoxGroupState<T, TValue>
  23. extends State<VSelectBoxButtonGroup<T, TValue>> {
  24. late TValue? _selectedValue;
  25. @override
  26. void initState() {
  27. _selectedValue = widget.value;
  28. super.initState();
  29. }
  30. @override
  31. Widget build(BuildContext context) {
  32. final children = <Widget>[];
  33. final length = widget.source.length;
  34. for (var i = 0; i < length; i++) {
  35. final e = widget.source[i];
  36. final value = widget.valueGetter(e);
  37. final isSelect = _selectedValue == value;
  38. children.add(VSelectBoxButton(
  39. // key: UniqueKey(),
  40. label: widget.labelGetter(e),
  41. isSelected: isSelect,
  42. onChanged: (status) {
  43. setState(() {
  44. if (status) {
  45. _onChanged(value);
  46. } else {
  47. _onChanged(null);
  48. }
  49. });
  50. }));
  51. }
  52. return Wrap(
  53. spacing: 12,
  54. runSpacing: 8,
  55. children: children,
  56. );
  57. }
  58. void _onChanged(TValue? value) {
  59. _selectedValue = value;
  60. widget.onChanged?.call(_selectedValue);
  61. }
  62. }
  63. class VSelectBoxButton extends StatefulWidget {
  64. final String label;
  65. final bool? isSelected;
  66. final ValueChanged<bool>? onChanged;
  67. const VSelectBoxButton(
  68. {super.key,
  69. required this.label,
  70. this.isSelected,
  71. required this.onChanged});
  72. @override
  73. State<StatefulWidget> createState() => _VSelectBoxState();
  74. }
  75. class _VSelectBoxState extends State<VSelectBoxButton> {
  76. bool _isSelected = false;
  77. @override
  78. void initState() {
  79. if (widget.isSelected != null) {
  80. _isSelected = widget.isSelected!;
  81. }
  82. super.initState();
  83. }
  84. @override
  85. void didUpdateWidget(covariant VSelectBoxButton oldWidget) {
  86. _isSelected=widget.isSelected==true;
  87. super.didUpdateWidget(oldWidget);
  88. }
  89. @override
  90. Widget build(BuildContext context) {
  91. const height = 56.0;
  92. const borderRadius = height / 2;
  93. final primaryColor = Theme.of(context).primaryColor;
  94. return Material(
  95. child: Ink(
  96. child: InkWell(
  97. borderRadius: BorderRadius.circular(borderRadius),
  98. onTap: () {
  99. setState(
  100. () {
  101. _isSelected = !_isSelected;
  102. widget.onChanged?.call(_isSelected);
  103. },
  104. );
  105. },
  106. child: Container(
  107. padding: const EdgeInsets.only(left: 0, right: borderRadius),
  108. alignment: Alignment.center,
  109. height: height,
  110. decoration: BoxDecoration(
  111. color: _isSelected ? primaryColor : Colors.white,
  112. borderRadius: BorderRadius.circular(borderRadius),
  113. border: _isSelected ? null : Border.all(color: primaryColor),
  114. ),
  115. child: Row(
  116. mainAxisSize: MainAxisSize.min,
  117. crossAxisAlignment: CrossAxisAlignment.center,
  118. children: [
  119. if (_isSelected) ...[
  120. const Icon(
  121. Icons.check_rounded,
  122. color: Colors.green,
  123. size: 24,
  124. ),
  125. const SizedBox(
  126. width: 8,
  127. ),
  128. ],
  129. if (!_isSelected)
  130. const SizedBox(
  131. width: 32,
  132. ),
  133. Text(
  134. widget.label,
  135. style: TextStyle(
  136. color: _isSelected ? Colors.white : primaryColor,
  137. fontSize: 20),
  138. )
  139. ],
  140. ),
  141. ),
  142. ),
  143. ),
  144. );
  145. }
  146. }