dialog_select.dart 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. import 'package:flutter/material.dart';
  2. import 'package:get/get.dart';
  3. import 'alert_dialog.dart';
  4. class VSelectModel {
  5. VSelectModel({required this.name, required this.code});
  6. final String name;
  7. final String code;
  8. }
  9. class VDialogSelect<T, TValue> extends StatelessWidget {
  10. /// 数据集
  11. final List<T> source;
  12. /// 初始值
  13. final TValue? initialValue;
  14. /// 弹窗标题
  15. final String? title;
  16. /// 选项文本提取函数
  17. final String Function(T data)? labelGetter;
  18. /// 选项外显组件构建器
  19. final Widget Function(T data)? labelBuilder;
  20. /// 选项值提取函数
  21. final TValue Function(T data) valueGetter;
  22. const VDialogSelect({
  23. super.key,
  24. required this.source,
  25. this.title,
  26. this.initialValue,
  27. this.labelGetter,
  28. this.labelBuilder,
  29. required this.valueGetter,
  30. }) : assert(labelGetter != null || labelBuilder != null);
  31. Future<T?> show<T>() => VAlertDialog.showDialog<T>(this);
  32. @override
  33. Widget build(BuildContext context) {
  34. return VAlertDialog(
  35. width: 460,
  36. title: title,
  37. content: Scrollbar(
  38. thumbVisibility: true,
  39. child: SingleChildScrollView(
  40. child: Column(
  41. mainAxisSize: MainAxisSize.min,
  42. children: _buildOptions(context),
  43. ),
  44. ),
  45. ),
  46. showCancel: true,
  47. );
  48. }
  49. List<Widget> _buildOptions(BuildContext context) {
  50. final primaryColor = Theme.of(context).primaryColor;
  51. final children = <Widget>[];
  52. for (var i = 0; i < source.length; i++) {
  53. final data = source[i];
  54. final val = valueGetter(data);
  55. final isSelected = initialValue == val;
  56. Widget label;
  57. if (labelBuilder != null) {
  58. label = labelBuilder!(data);
  59. } else {
  60. label = Text(
  61. labelGetter!(data),
  62. style: TextStyle(
  63. color: isSelected ? primaryColor : Colors.black,
  64. fontSize: 20,
  65. ),
  66. );
  67. }
  68. final widget = Container(
  69. alignment: Alignment.centerLeft,
  70. height: 56,
  71. padding: const EdgeInsets.symmetric(horizontal: 8),
  72. color: isSelected ? Theme.of(context).secondaryHeaderColor : null,
  73. child: Row(
  74. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  75. children: [
  76. Row(
  77. mainAxisSize: MainAxisSize.min,
  78. children: [const SizedBox(width: 20), label],
  79. ),
  80. if (isSelected)
  81. Row(
  82. children: [
  83. Icon(
  84. Icons.check,
  85. size: 24,
  86. color: primaryColor,
  87. ),
  88. const SizedBox(width: 20)
  89. ],
  90. ),
  91. ],
  92. ),
  93. );
  94. children.add(
  95. Material(
  96. color: Colors.transparent,
  97. child: Ink(
  98. child: InkWell(
  99. onTap: () {
  100. _onSelected(val);
  101. },
  102. child: widget,
  103. ),
  104. ),
  105. ),
  106. );
  107. }
  108. return children;
  109. }
  110. void _onSelected(TValue value) {
  111. Get.back(result: value);
  112. }
  113. }