step_card.dart 4.8 KB

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