step_card.dart 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. import 'package:flutter/cupertino.dart';
  2. import 'package:flutter_screenutil/flutter_screenutil.dart';
  3. import '../../../resource/colors.gen.dart';
  4. import '../../../widget/gradient_text.dart';
  5. import '../intimacy_analyse_upload/widget/step_label_widget.dart';
  6. /// 步骤卡片,支持设置卡片背景、步骤标题、步骤描述、顶部图标和内容区域
  7. class StepCard extends StatelessWidget {
  8. /// 卡片背景
  9. final ImageProvider? bgImageProvider;
  10. /// 步骤标签
  11. final String? stepLabel;
  12. /// 步骤标题
  13. final String? stepTitle;
  14. /// 步骤描述
  15. final String? stepDesc;
  16. /// 顶部图标
  17. final Image? topIconWidget;
  18. /// 内容组件
  19. final Widget contentWidget;
  20. /// 是否有步骤
  21. final bool hasStep;
  22. const StepCard({
  23. super.key,
  24. this.bgImageProvider,
  25. this.stepLabel,
  26. this.stepTitle,
  27. this.stepDesc,
  28. this.hasStep = true,
  29. required this.contentWidget,
  30. this.topIconWidget,
  31. });
  32. @override
  33. Widget build(BuildContext context) {
  34. BoxDecoration decoration;
  35. // 没有背景图,使用渐变背景
  36. if (bgImageProvider == null) {
  37. decoration = BoxDecoration(
  38. gradient: LinearGradient(
  39. colors: [Color(0xFFEFE9FF), Color(0xFFFBFAFF)],
  40. begin: Alignment.topCenter,
  41. end: Alignment.bottomRight,
  42. ),
  43. shape: BoxShape.rectangle,
  44. border: Border.all(color: ColorName.white80, width: 1.w),
  45. borderRadius: BorderRadius.all(Radius.circular(20.r)),
  46. );
  47. } else {
  48. // 背景图
  49. decoration = BoxDecoration(
  50. image: DecorationImage(image: bgImageProvider!, fit: BoxFit.fill),
  51. );
  52. }
  53. return Container(
  54. margin: EdgeInsets.only(left: 12.w, top: 10.h, right: 12.w),
  55. child: Stack(
  56. // 不裁切超出区域的子组件,例如下面的顶部的图标
  57. clipBehavior: Clip.none,
  58. children: [
  59. // 顶部的图标
  60. topIconWidget == null
  61. ? SizedBox()
  62. : Positioned(top: -11.h, right: 0, child: topIconWidget!),
  63. // 卡片背景
  64. Container(
  65. decoration: decoration,
  66. child: Column(
  67. // 左对齐
  68. crossAxisAlignment: CrossAxisAlignment.start,
  69. children: [
  70. _buildStepLayout(),
  71. // 内容区域
  72. contentWidget,
  73. SizedBox(height: 12.h),
  74. ],
  75. ),
  76. ),
  77. ],
  78. ),
  79. );
  80. }
  81. /// 步骤
  82. Widget _buildStepLayout() {
  83. if (!hasStep) {
  84. return SizedBox();
  85. }
  86. String stepDescStr = stepDesc ?? "";
  87. return Column(
  88. children: [
  89. // 步骤标题
  90. Container(
  91. margin: EdgeInsets.only(
  92. // 存在步骤标签时,才有左边距
  93. left: _hasStepLabel() ? 12.w : 0,
  94. top: 16.h,
  95. bottom: 4.h,
  96. ),
  97. child: _buildStepTitle(),
  98. ),
  99. SizedBox(height: 4.h),
  100. // 步骤描述
  101. stepDescStr.isNotEmpty
  102. ? _buildStepDesc(stepDescStr)
  103. : SizedBox(height: 6.h),
  104. SizedBox(height: 14.h),
  105. ],
  106. );
  107. }
  108. /// 是否有步骤标签
  109. bool _hasStepLabel() {
  110. String stepLabelStr = stepLabel ?? "";
  111. return stepLabelStr.isNotEmpty == true;
  112. }
  113. /// 是否有步骤标题
  114. bool _hasStepTitle() {
  115. String stepTitleStr = stepTitle ?? "";
  116. return stepTitleStr.isNotEmpty == true;
  117. }
  118. /// 是否有步骤标题
  119. bool _hasStepDesc() {
  120. String stepDescStr = stepDesc ?? "";
  121. return stepDescStr.isNotEmpty == true;
  122. }
  123. /// 步骤标题
  124. Widget _buildStepTitle() {
  125. String stepTitleStr = stepTitle ?? "";
  126. // 步骤标签
  127. Widget stepLabelWidget;
  128. if (_hasStepLabel()) {
  129. stepLabelWidget = StepLabelWidget(label: stepLabel ?? "");
  130. } else {
  131. stepLabelWidget = SizedBox();
  132. }
  133. return Row(
  134. children: [
  135. // 步骤标签
  136. stepLabelWidget,
  137. SizedBox(width: 10.w),
  138. // 标题
  139. GradientText(
  140. // 渐变颜色
  141. colors: [ColorName.stepTitleColor1, ColorName.stepTitleColor2],
  142. child: Text(
  143. stepTitleStr,
  144. style: TextStyle(fontSize: 20.sp, fontWeight: FontWeight.w700),
  145. ),
  146. ),
  147. ],
  148. );
  149. }
  150. /// 构建步骤描述
  151. Widget _buildStepDesc(String desc) {
  152. if (desc.isEmpty) {
  153. return SizedBox();
  154. }
  155. return Row(
  156. children: [
  157. Expanded(
  158. child: Container(
  159. margin: EdgeInsets.only(left: 12.w, right: 12.w),
  160. child: Text(
  161. desc,
  162. // 超过时显示省略号
  163. overflow: TextOverflow.ellipsis,
  164. // 最多多少行
  165. maxLines: 2,
  166. style: TextStyle(
  167. fontSize: 12.sp,
  168. fontWeight: FontWeight.w400,
  169. color: ColorName.black60,
  170. ),
  171. ),
  172. ),
  173. ),
  174. SizedBox(height: 16.h),
  175. ],
  176. );
  177. }
  178. }