dialog_check.dart 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. import 'package:flutter/material.dart';
  2. import 'package:get/get.dart';
  3. import 'package:vitalapp/components/alert_dialog.dart';
  4. class VDialogCheck<T, TValue> extends StatefulWidget {
  5. const VDialogCheck({
  6. Key? key,
  7. this.title,
  8. required this.source,
  9. required this.initialValue,
  10. this.labelGetter,
  11. required this.valueGetter,
  12. // ignore: non_constant_identifier_names
  13. this.MutexValue,
  14. }) : super(key: key);
  15. final String? title;
  16. final List<T> source;
  17. final List<TValue> initialValue;
  18. // ignore: non_constant_identifier_names
  19. final TValue? MutexValue;
  20. /// 选项文本提取函数
  21. final String Function(T data)? labelGetter;
  22. /// 选项值提取函数
  23. final TValue Function(T data) valueGetter;
  24. @override
  25. // ignore: library_private_types_in_public_api
  26. _VDialogCheckState<T, TValue> createState() =>
  27. _VDialogCheckState<T, TValue>();
  28. Future<T?> show<T>() => VAlertDialog.showDialog<T>(this);
  29. }
  30. class _VDialogCheckState<T, TValue> extends State<VDialogCheck<T, TValue>> {
  31. List<TValue> initialValue = [];
  32. @override
  33. void initState() {
  34. super.initState();
  35. initialValue = widget.initialValue.toList();
  36. }
  37. @override
  38. Widget build(BuildContext context) {
  39. return VAlertDialog(
  40. width: 460,
  41. title: widget.title,
  42. content: Scrollbar(
  43. thumbVisibility: true,
  44. child: SingleChildScrollView(
  45. child: Column(
  46. mainAxisSize: MainAxisSize.min,
  47. children: _buildOptions(context),
  48. ),
  49. ),
  50. ),
  51. onConfirm: () {
  52. Get.back(result: initialValue);
  53. },
  54. );
  55. }
  56. List<Widget> _buildOptions(BuildContext context) {
  57. final primaryColor = Theme.of(context).primaryColor;
  58. final children = <Widget>[];
  59. for (var i = 0; i < widget.source.length; i++) {
  60. final data = widget.source[i];
  61. final val = widget.valueGetter(data);
  62. final isSelected = initialValue.contains(val);
  63. Widget label;
  64. label = Text(
  65. widget.labelGetter!(data),
  66. style: TextStyle(
  67. color: isSelected ? primaryColor : Colors.black,
  68. fontSize: 20,
  69. ),
  70. );
  71. final widgetItem = Container(
  72. alignment: Alignment.centerLeft,
  73. height: 56,
  74. padding: const EdgeInsets.symmetric(horizontal: 8),
  75. color: isSelected ? Theme.of(context).secondaryHeaderColor : null,
  76. child: Row(
  77. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  78. children: [
  79. Row(
  80. mainAxisSize: MainAxisSize.min,
  81. children: [
  82. const SizedBox(
  83. width: 20,
  84. ),
  85. label
  86. ],
  87. ),
  88. if (isSelected)
  89. Row(
  90. children: [
  91. Icon(
  92. Icons.check,
  93. size: 24,
  94. color: primaryColor,
  95. ),
  96. const SizedBox(
  97. width: 20,
  98. )
  99. ],
  100. )
  101. ],
  102. ),
  103. );
  104. children.add(
  105. Material(
  106. color: Colors.transparent,
  107. child: Ink(
  108. child: InkWell(
  109. onTap: () {
  110. final val = widget.valueGetter(data);
  111. if (!(widget.MutexValue != null &&
  112. initialValue.contains(widget.MutexValue)) ||
  113. val == widget.MutexValue) {
  114. setState(() {
  115. if (val == widget.MutexValue &&
  116. !initialValue.contains(widget.MutexValue)) {
  117. initialValue.clear();
  118. }
  119. if (initialValue.contains(val)) {
  120. initialValue.remove(val);
  121. } else {
  122. initialValue.add(val);
  123. }
  124. });
  125. }
  126. },
  127. child: widgetItem,
  128. )),
  129. ),
  130. );
  131. }
  132. return children;
  133. }
  134. }