option_select_widget.dart 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. import 'package:cached_network_image/cached_network_image.dart';
  2. import 'package:flutter/cupertino.dart';
  3. import 'package:flutter/material.dart';
  4. import 'package:flutter_screenutil/flutter_screenutil.dart';
  5. import 'package:keyboard/data/bean/option_select_item.dart';
  6. import '../../../data/bean/option_select_config.dart';
  7. import '../../../resource/colors.gen.dart';
  8. /// 切换选中时回调
  9. typedef OnOptionSelectCallback =
  10. void Function(OptionSelectConfig config, OptionSelectItem optionItem);
  11. /// 选项选择组件
  12. class OptionSelectWidget extends StatelessWidget {
  13. /// 选项行的配置
  14. final OptionSelectConfig optionSelect;
  15. /// 切换选中时回调
  16. final OnOptionSelectCallback optionSelectCallback;
  17. const OptionSelectWidget({
  18. super.key,
  19. required this.optionSelect,
  20. required this.optionSelectCallback,
  21. });
  22. @override
  23. Widget build(BuildContext context) {
  24. return Column(
  25. crossAxisAlignment: CrossAxisAlignment.start,
  26. children: [
  27. // 标题
  28. _buildTitle(),
  29. SizedBox(height: 16.h),
  30. // 选项
  31. _buildOptionList(),
  32. ],
  33. );
  34. }
  35. /// 图标和标题
  36. Widget _buildTitle() {
  37. String icon = optionSelect.iconUrl;
  38. return Row(
  39. children: [
  40. Visibility(
  41. visible: icon.isNotEmpty,
  42. child: Row(
  43. children: [
  44. // 图标
  45. CachedNetworkImage(
  46. imageUrl: icon,
  47. height: 14.h,
  48. width: 14.w,
  49. fit: BoxFit.fill,
  50. ),
  51. SizedBox(width: 2),
  52. ],
  53. ),
  54. ),
  55. // 标题
  56. Text(
  57. optionSelect.title,
  58. style: TextStyle(
  59. fontSize: 14.sp,
  60. fontWeight: FontWeight.w700,
  61. color: ColorName.black80,
  62. ),
  63. ),
  64. ],
  65. );
  66. }
  67. /// 选项列表
  68. Widget _buildOptionList() {
  69. // 固定一行3列,每项的宽度一样
  70. return GridView.builder(
  71. // 去掉默认的Padding,默认会有一个默认的顶部padding大小
  72. padding: EdgeInsets.zero,
  73. // 包裹内容
  74. shrinkWrap: true,
  75. // 禁止滚动
  76. physics: const NeverScrollableScrollPhysics(),
  77. gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
  78. // 一行3列
  79. crossAxisCount: 3,
  80. // 水平方向的间距
  81. crossAxisSpacing: 6.0,
  82. // 垂直方向的间距
  83. mainAxisSpacing: 12.0,
  84. // 子项的宽高比
  85. childAspectRatio: 2.6,
  86. ),
  87. itemCount: optionSelect.options.length,
  88. itemBuilder: (context, index) {
  89. OptionSelectItem option = optionSelect.options[index];
  90. return _buildOptionItem(optionSelect, option);
  91. },
  92. );
  93. // 流式布局,类似安卓的FlowLayout,1列不固定3个,放不下就自动换行
  94. // return Wrap(
  95. // direction: Axis.horizontal,
  96. // alignment: WrapAlignment.start,
  97. // // 主轴间距
  98. // spacing: 8.0,
  99. // // 交叉轴间距
  100. // runSpacing: 7.0,
  101. // children: [
  102. // for (var option in optionSelect.options)
  103. // _buildOptionItem(optionSelect, option),
  104. // ],
  105. // );
  106. }
  107. /// 选项
  108. /// [rowConfig] 选项行的配置
  109. /// [optionItem] 当前构建的那一项
  110. Widget _buildOptionItem(
  111. OptionSelectConfig rowConfig,
  112. OptionSelectItem optionItem,
  113. ) {
  114. // 背景圆角
  115. double bgBorderRadius = 31.r;
  116. // 背景,选中时为渐变色,未选中时为灰色
  117. BoxDecoration bgDecoration;
  118. if (optionItem.selected) {
  119. bgDecoration = BoxDecoration(
  120. gradient: LinearGradient(
  121. colors: [
  122. ColorName.bgOptionSelectSelected1,
  123. ColorName.bgOptionSelectSelected2,
  124. ],
  125. begin: Alignment.centerLeft,
  126. end: Alignment.centerRight,
  127. ),
  128. borderRadius: BorderRadius.circular(bgBorderRadius),
  129. );
  130. } else {
  131. bgDecoration = BoxDecoration(
  132. color: ColorName.bgOptionSelectNormal,
  133. borderRadius: BorderRadius.circular(bgBorderRadius),
  134. );
  135. }
  136. return GestureDetector(
  137. onTap: () {
  138. optionSelectCallback(rowConfig, optionItem);
  139. },
  140. child: Container(
  141. // padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 6.h),
  142. decoration: bgDecoration,
  143. child: Center(
  144. child: Text(
  145. optionItem.name,
  146. maxLines: 1,
  147. style: TextStyle(
  148. overflow: TextOverflow.ellipsis,
  149. fontSize: 13.sp,
  150. fontWeight: FontWeight.w400,
  151. // 文字颜色,选中时为白色,未选中时为黑色
  152. color: optionItem.selected ? ColorName.white : ColorName.black80,
  153. ),
  154. ),
  155. ),
  156. ),
  157. );
  158. }
  159. }