coupon_view.dart 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  1. import 'package:bbyyy/beans/my_coupon_bean_entity.dart';
  2. import 'package:bbyyy/my_tools/const.dart';
  3. import 'package:bbyyy/my_tools/event_bus.dart';
  4. import 'package:bbyyy/my_tools/my_colors.dart';
  5. import 'package:flutter/cupertino.dart';
  6. import 'package:flutter/material.dart';
  7. import 'package:flutter_svg/flutter_svg.dart';
  8. class CouponView {
  9. CouponView._internal();
  10. //保存单例
  11. static CouponView _singleton = CouponView._internal();
  12. //工厂构造函数
  13. factory CouponView() => _singleton;
  14. ticketItem(MyCouponBeanDataData data) {
  15. return StatefulBuilder(builder:
  16. (BuildContext context, void Function(void Function()) setState) {
  17. return Column(
  18. children: [
  19. Container(
  20. height: 124,
  21. margin: EdgeInsets.only(top: 20),
  22. width: double.infinity,
  23. child: ClipShadowPath(
  24. clipper: TicketClipPath(),
  25. shadow: Shadow(blurRadius: 5, color: MyColors.c21333333),
  26. child: Scaffold(
  27. body: Stack(
  28. children: [
  29. Column(
  30. children: [
  31. Padding(
  32. padding: const EdgeInsets.only(
  33. left: 16, top: 9, right: 14),
  34. child: Row(
  35. children: [
  36. Stack(
  37. children: [
  38. Container(
  39. child: SvgPicture.asset(
  40. 'images/svg/优惠券(1).svg',
  41. height: 69,
  42. width: 69,
  43. ),
  44. margin: EdgeInsets.only(right: 12),
  45. ),
  46. Container(
  47. height: 69,
  48. width: 69,
  49. padding: EdgeInsets.only(
  50. bottom: 14,
  51. left: 16,
  52. ),
  53. child: Row(
  54. children: [
  55. Container(
  56. child: Text(
  57. '¥',
  58. style: TextStyle(
  59. color: Colors.white,
  60. fontSize: 12),
  61. ),
  62. padding: EdgeInsets.only(bottom: 2),
  63. ),
  64. Text(
  65. '${data.amount}',
  66. style: TextStyle(
  67. color: Colors.white,
  68. fontSize: 18),
  69. ),
  70. ],
  71. crossAxisAlignment:
  72. CrossAxisAlignment.end,
  73. mainAxisAlignment:
  74. MainAxisAlignment.start,
  75. ),
  76. ),
  77. ],
  78. ),
  79. Expanded(
  80. child: Column(
  81. children: [
  82. Text(
  83. couponType(data.type),
  84. style: TextStyle(
  85. color: MyColors.c333333,
  86. fontSize: 14),
  87. ),
  88. Container(
  89. margin: EdgeInsets.only(top: 10),
  90. child: Text(
  91. '有效期至${data.expireDate}',
  92. style: TextStyle(
  93. color: MyColors.c999999,
  94. fontSize: 10),
  95. ),
  96. ),
  97. ],
  98. crossAxisAlignment: CrossAxisAlignment.start,
  99. ),
  100. ),
  101. ],
  102. ),
  103. ),
  104. Padding(
  105. padding:
  106. EdgeInsets.only(left: 16, right: 15, bottom: 7),
  107. child: Row(
  108. children: [
  109. Visibility(
  110. visible: DateTime.parse(data.expireDate)
  111. .subtract(Duration(days: 1))
  112. .isBefore(DateTime.now()) ||
  113. data.used,
  114. child: Container(
  115. height: 18,
  116. width: 46,
  117. decoration: BoxDecoration(
  118. border: Border.all(
  119. color: data.used
  120. ? MyColors.cFF4233
  121. : MyColors.cC6C6C6,
  122. width: 0.5),
  123. borderRadius: BorderRadius.all(
  124. Radius.circular(4),
  125. ),
  126. ),
  127. child: Text(
  128. data.used ? '已使用' : '即将到期',
  129. style: TextStyle(
  130. color: data.used
  131. ? MyColors.cFF4233
  132. : MyColors.c999999,
  133. fontSize: 9),
  134. ),
  135. alignment: Alignment.center,
  136. ),
  137. ),
  138. Expanded(
  139. child: GestureDetector(
  140. onTap: () {
  141. data.showDetail = !data.showDetail;
  142. EventBus().emit('showCouponIndex');
  143. },
  144. behavior: HitTestBehavior.translucent,
  145. child: Container(
  146. padding: EdgeInsets.all(1),
  147. child: Row(
  148. children: [
  149. Text(
  150. '使用规则',
  151. style: TextStyle(
  152. color: MyColors.c999999,
  153. fontSize: 11),
  154. ),
  155. Icon(
  156. data.showDetail
  157. ? Icons.arrow_drop_up
  158. : Icons.arrow_drop_down,
  159. color: MyColors.c999999,
  160. size: 20,
  161. )
  162. ],
  163. mainAxisAlignment: MainAxisAlignment.end,
  164. ),
  165. ),
  166. ),
  167. ),
  168. ],
  169. ),
  170. )
  171. ],
  172. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  173. ),
  174. Container(
  175. child: CustomPaint(
  176. painter: DashedPainter(),
  177. size: Size(double.infinity, 1),
  178. ),
  179. margin: EdgeInsets.only(
  180. top: 124 / 25 * 18, right: 10, left: 10),
  181. )
  182. ],
  183. ),
  184. ),
  185. ),
  186. ),
  187. AnimatedOpacity(
  188. duration: Duration(milliseconds: 200),
  189. opacity: data.showDetail ? 1 : 0,
  190. child: Visibility(
  191. visible: data.showDetail,
  192. child: Container(
  193. width: double.infinity,
  194. height: 114,
  195. margin: EdgeInsets.only(top: 4),
  196. child: ClipShadowPath(
  197. shadow: Shadow(blurRadius: 5, color: MyColors.c21333333),
  198. clipper: DescriptionClipPath(),
  199. child: Scaffold(
  200. body: Column(
  201. children: [
  202. Container(
  203. margin: EdgeInsets.only(top: 16),
  204. child: Text(
  205. '使用规则',
  206. style: TextStyle(
  207. color: MyColors.c999999, fontSize: 12),
  208. ),
  209. alignment: Alignment.center,
  210. width: double.infinity,
  211. ),
  212. Container(
  213. margin: EdgeInsets.symmetric(horizontal: 29),
  214. child: Text(
  215. couponRule(data.type),
  216. style: TextStyle(
  217. color: MyColors.c999999, fontSize: 12),
  218. ),
  219. ),
  220. ],
  221. crossAxisAlignment: CrossAxisAlignment.start,
  222. ),
  223. ),
  224. ),
  225. ),
  226. ),
  227. )
  228. ],
  229. );
  230. });
  231. }
  232. }
  233. class TicketClipPath extends CustomClipper<Path> {
  234. @override
  235. Path getClip(Size size) {
  236. print(size);
  237. var path = Path()
  238. ..moveTo(0, 4)
  239. ..quadraticBezierTo(0, 0, 4, 0)
  240. ..lineTo(size.width - 4, 0)
  241. ..quadraticBezierTo(size.width, 0, size.width, 4)
  242. ..lineTo(size.width, size.height / 25 * 18 - 6)
  243. ..quadraticBezierTo(size.width - 6, size.height / 25 * 18 - 6,
  244. size.width - 6, size.height / 25 * 18)
  245. ..quadraticBezierTo(size.width - 6, size.height / 25 * 18 + 6, size.width,
  246. size.height / 25 * 18 + 6)
  247. ..lineTo(size.width, size.height - 4)
  248. ..quadraticBezierTo(size.width, size.height, size.width - 4, size.height)
  249. ..lineTo(4, size.height)
  250. ..quadraticBezierTo(0, size.height, 0, size.height - 4)
  251. ..lineTo(0, size.height / 25 * 18 + 6)
  252. ..quadraticBezierTo(
  253. 6, size.height / 25 * 18 + 6, 6, size.height / 25 * 18)
  254. ..quadraticBezierTo(
  255. 6, size.height / 25 * 18 - 6, 0, size.height / 25 * 18 - 6)
  256. ..close();
  257. return path;
  258. }
  259. @override
  260. bool shouldReclip(CustomClipper<Path> oldClipper) => false;
  261. }
  262. class TicketClipPath2 extends CustomClipper<Path> {
  263. @override
  264. Path getClip(Size size) {
  265. print(size);
  266. var path = Path()
  267. ..moveTo(0, 4)
  268. ..quadraticBezierTo(0, 0, 4, 0)
  269. ..lineTo(size.width - 4, 0)
  270. ..quadraticBezierTo(size.width, 0, size.width, 4)
  271. ..lineTo(size.width, size.height - 39 - 6)
  272. ..quadraticBezierTo(size.width - 6, size.height - 39 - 6, size.width - 6,
  273. size.height - 39)
  274. ..quadraticBezierTo(size.width - 6, size.height - 39 + 6, size.width,
  275. size.height - 39 + 6)
  276. ..lineTo(size.width, size.height - 4)
  277. ..quadraticBezierTo(size.width, size.height, size.width - 4, size.height)
  278. ..lineTo(4, size.height)
  279. ..quadraticBezierTo(0, size.height, 0, size.height - 4)
  280. ..lineTo(0, size.height - 39 + 6)
  281. ..quadraticBezierTo(6, size.height - 39 + 6, 6, size.height - 39)
  282. ..quadraticBezierTo(6, size.height - 39 - 6, 0, size.height - 39 - 6)
  283. ..close();
  284. return path;
  285. }
  286. @override
  287. bool shouldReclip(CustomClipper<Path> oldClipper) => false;
  288. }
  289. class DescriptionClipPath extends CustomClipper<Path> {
  290. @override
  291. Path getClip(Size size) {
  292. double h = size.height;
  293. double w = size.width;
  294. var path = Path()
  295. ..moveTo(0, 10)
  296. ..quadraticBezierTo(0, 6, 4, 6)
  297. ..lineTo(w - 25, 6)
  298. ..lineTo(w - 19, 0)
  299. ..lineTo(w - 13, 6)
  300. ..lineTo(w - 4, 6)
  301. ..quadraticBezierTo(w, 6, w, 10)
  302. ..lineTo(w, h - 4)
  303. ..quadraticBezierTo(w, h, w - 4, h)
  304. ..lineTo(4, h)
  305. ..quadraticBezierTo(0, h, 0, h - 4)
  306. ..close();
  307. return path;
  308. }
  309. @override
  310. bool shouldReclip(CustomClipper<Path> oldClipper) => false;
  311. }
  312. class ClipShadowPath extends StatelessWidget {
  313. final Shadow shadow;
  314. final CustomClipper<Path> clipper;
  315. final Widget child;
  316. ClipShadowPath({
  317. @required this.shadow,
  318. @required this.clipper,
  319. @required this.child,
  320. });
  321. @override
  322. Widget build(BuildContext context) {
  323. return CustomPaint(
  324. key: UniqueKey(),
  325. painter: _ClipShadowShadowPainter(
  326. clipper: this.clipper,
  327. shadow: this.shadow,
  328. ),
  329. child: ClipPath(child: child, clipper: this.clipper),
  330. );
  331. }
  332. }
  333. class _ClipShadowShadowPainter extends CustomPainter {
  334. final Shadow shadow;
  335. final CustomClipper<Path> clipper;
  336. _ClipShadowShadowPainter({@required this.shadow, @required this.clipper});
  337. @override
  338. void paint(Canvas canvas, Size size) {
  339. var paint = shadow.toPaint();
  340. var clipPath = clipper.getClip(size).shift(shadow.offset);
  341. canvas.drawPath(clipPath, paint);
  342. }
  343. @override
  344. bool shouldRepaint(CustomPainter oldDelegate) {
  345. return true;
  346. }
  347. }
  348. class DashedPainter extends CustomPainter {
  349. @override
  350. void paint(Canvas canvas, Size size) {
  351. var paint = Paint() // 创建一个画笔并配置其属性
  352. ..strokeWidth = 1 // 画笔的宽度
  353. ..isAntiAlias = true // 是否抗锯齿
  354. ..color = Color(0xffdbdbdb); // 画笔颜色
  355. var max = size.width; // size获取到宽度
  356. var dashWidth = 5;
  357. var dashSpace = 5;
  358. double startX = 0;
  359. final space = (dashSpace + dashWidth);
  360. while (startX < max) {
  361. canvas.drawLine(
  362. Offset(startX, 0.0), Offset(startX + dashWidth, 0.0), paint);
  363. startX += space;
  364. }
  365. }
  366. @override
  367. bool shouldRepaint(CustomPainter oldDelegate) => false;
  368. }