基础组件库
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

207 lines
6.5 KiB

  1. import 'dart:async';
  2. import 'package:flutter/material.dart';
  3. import 'package:flutter_bloc/flutter_bloc.dart';
  4. import 'package:cached_network_image/cached_network_image.dart';
  5. import 'package:zhiying_comm/zhiying_comm.dart';
  6. import 'bloc/bloc.dart';
  7. import 'custom_notice_sk.dart';
  8. ///
  9. /// 公告滚动widget
  10. ///
  11. class CustomNoticeWidget extends StatelessWidget {
  12. final Map<String, dynamic> model;
  13. const CustomNoticeWidget(this.model);
  14. @override
  15. Widget build(BuildContext context) {
  16. return BlocProvider<CustomNoticeBloc>(
  17. create: (_) => CustomNoticeBloc(repository: CustomNoticeRepository())..add(CustomNoticeInitEvent(model: model)),
  18. child: _CustomNoticeWidgetContainer(),
  19. );
  20. }
  21. }
  22. class _CustomNoticeWidgetContainer extends StatefulWidget {
  23. @override
  24. _CustomNoticeWidgetContainerState createState() => _CustomNoticeWidgetContainerState();
  25. }
  26. class _CustomNoticeWidgetContainerState extends State<_CustomNoticeWidgetContainer> {
  27. /// 子item点击事件
  28. void _itemOnClick(CustomNoticeModel model) {
  29. if (pageIndex == model.listStyle.length) {
  30. pageIndex = 0;
  31. }
  32. print('===== $pageIndex');
  33. NoticeListStyle item = model.listStyle[pageIndex];
  34. _itemJump(item);
  35. }
  36. /// 子item跳转
  37. void _itemJump(NoticeListStyle model) {
  38. print('${model?.contentText}');
  39. RouterUtil.route(model, model.toJson(), context);
  40. }
  41. @override
  42. Widget build(BuildContext context) {
  43. return BlocConsumer<CustomNoticeBloc, CustomNoticeState>(
  44. listener: (context, state) {},
  45. buildWhen: (prev, current) {
  46. return true;
  47. },
  48. builder: (context, state) {
  49. if (state is CustomNoticeLoadedState) {
  50. return _getMainWidget(state?.model);
  51. }
  52. return CustomNoticeSkeleton();
  53. },
  54. );
  55. }
  56. /// 主体页面
  57. Widget _getMainWidget(CustomNoticeModel model) {
  58. return Container(
  59. width: double.infinity,
  60. decoration: BoxDecoration(
  61. color: HexColor.fromHex(model?.bgColor),
  62. // color: Colors.orangeAccent,
  63. borderRadius: BorderRadius.only(
  64. topRight: Radius.circular(ParseUtil.stringParseDouble(model?.topRightRadius, defVal: 7.5)),
  65. topLeft: Radius.circular(ParseUtil.stringParseDouble(model?.topLeftRadius, defVal: 7.5)),
  66. bottomLeft: Radius.circular(ParseUtil.stringParseDouble(model?.bottomLeftRadius, defVal: 7.5)),
  67. bottomRight: Radius.circular(ParseUtil.stringParseDouble(model?.bottomRightRadius, defVal: 7.5)),
  68. )),
  69. margin: EdgeInsets.only(top: ParseUtil.stringParseDouble(model?.topMargin)),
  70. padding: EdgeInsets.symmetric(horizontal: ParseUtil.stringParseDouble(model?.leftRightMargin, defVal: 12.5), vertical: 7.5),
  71. child: Container(
  72. decoration: BoxDecoration(borderRadius: BorderRadius.circular(7.5), color: HexColor.fromHex('#F6F6F6')),
  73. padding: const EdgeInsets.only(top: 8, bottom: 8, left: 12, right: 8),
  74. width: double.infinity,
  75. child: _getChildWidget(model),
  76. ),
  77. );
  78. }
  79. var pageIndex = 0;
  80. Widget _getChildWidget(CustomNoticeModel model) {
  81. return GestureDetector(
  82. onTap: () => _itemOnClick(model),
  83. behavior: HitTestBehavior.opaque,
  84. child: Row(
  85. children: <Widget>[
  86. /// 图片
  87. // Container(width: 52, height: 13, color: Colors.red),
  88. CachedNetworkImage(
  89. imageUrl: model?.appNameImg ?? '',
  90. width: 52,
  91. ),
  92. const SizedBox(width: 14),
  93. /// 文字
  94. Expanded(
  95. child: Container(
  96. width: double.infinity,
  97. height: 15,
  98. alignment: Alignment.centerLeft,
  99. // color: Colors.yellowAccent,
  100. child: MarqueeWidget(
  101. model?.listStyle?.length ?? 0,
  102. (BuildContext context, int index) {
  103. NoticeListStyle item = model.listStyle[index];
  104. return Align(alignment: Alignment.centerLeft, child: Text('${item?.contentText}', style: TextStyle(color: HexColor.fromHex(model?.textColor), fontSize: 12)));
  105. },
  106. onPageChanged: (index) => pageIndex = index,
  107. ),
  108. ),
  109. ),
  110. const SizedBox(width: 14),
  111. /// 图片
  112. CachedNetworkImage(imageUrl: model?.jumpImg ?? '', height: 18),
  113. // Container(
  114. // width: 18,
  115. // height: 18,
  116. // color: Colors.red,
  117. // ),
  118. ],
  119. ),
  120. );
  121. }
  122. }
  123. // 上下滚动的消息轮播
  124. class MarqueeWidget extends StatefulWidget {
  125. int count; // 子视图数量
  126. IndexedWidgetBuilder itemBuilder; // 子视图构造器
  127. final ValueChanged<int> onPageChanged;
  128. MarqueeWidget(this.count, this.itemBuilder, {this.onPageChanged});
  129. @override
  130. _MarqueeWidgetState createState() => _MarqueeWidgetState();
  131. }
  132. class _MarqueeWidgetState extends State<MarqueeWidget> {
  133. PageController _controller;
  134. Timer _timer;
  135. @override
  136. void initState() {
  137. super.initState();
  138. if (widget.count > 0) {
  139. _controller = PageController();
  140. _timer = Timer.periodic(Duration(seconds: 5), (timer) {
  141. // 如果当前位于最后一页,则直接跳转到第一页,两者内容相同,跳转时视觉上无感知
  142. if (_controller.page.round() >= widget.count) {
  143. _controller.jumpToPage(0);
  144. }
  145. _controller.nextPage(duration: Duration(seconds: 1), curve: Curves.linear);
  146. });
  147. }
  148. }
  149. @override
  150. Widget build(BuildContext context) {
  151. // return PageView.builder(
  152. // scrollDirection: Axis.vertical,
  153. // controller: _controller,
  154. // itemBuilder: (buildContext, index) {
  155. // if (index < widget.count) {
  156. // return widget.itemBuilder(buildContext, index);
  157. // } else {
  158. // return widget.itemBuilder(buildContext, 0);
  159. // }
  160. // },
  161. // itemCount: widget.count + 1, // 在原数据末尾添加一笔数据(即第一笔数据),用于实现无限循环滚动效果
  162. // );
  163. // }
  164. return PageView.custom(
  165. physics: NeverScrollableScrollPhysics(),
  166. childrenDelegate: SliverChildBuilderDelegate((context, index) {
  167. if (index < widget.count) {
  168. return widget.itemBuilder(context, index);
  169. } else {
  170. return widget.itemBuilder(context, 0);
  171. }
  172. }, childCount: widget.count + 1),
  173. scrollDirection: Axis.vertical,
  174. controller: _controller,
  175. onPageChanged: widget?.onPageChanged,
  176. );
  177. }
  178. @override
  179. void dispose() {
  180. super.dispose();
  181. _controller?.dispose();
  182. _timer?.cancel();
  183. }
  184. }