基础组件库
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.
 
 
 
 
 

210 lines
6.7 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(
  70. top: ParseUtil.stringParseDouble(model?.topMargin),
  71. left: ParseUtil.stringParseDouble(model?.leftRightMargin),
  72. right: ParseUtil.stringParseDouble(model?.leftRightMargin)),
  73. padding: EdgeInsets.symmetric(horizontal: ParseUtil.stringParseDouble(model?.leftRightMargin, defVal: 12.5), vertical: 7.5),
  74. child: Container(
  75. decoration: BoxDecoration(borderRadius: BorderRadius.circular(7.5), color: HexColor.fromHex('#F6F6F6')),
  76. padding: const EdgeInsets.only(top: 8, bottom: 8, left: 12, right: 8),
  77. width: double.infinity,
  78. child: _getChildWidget(model),
  79. ),
  80. );
  81. }
  82. var pageIndex = 0;
  83. Widget _getChildWidget(CustomNoticeModel model) {
  84. return GestureDetector(
  85. onTap: () => _itemOnClick(model),
  86. behavior: HitTestBehavior.opaque,
  87. child: Row(
  88. children: <Widget>[
  89. /// 图片
  90. // Container(width: 52, height: 13, color: Colors.red),
  91. CachedNetworkImage(
  92. imageUrl: model?.appNameImg ?? '',
  93. width: 52,
  94. ),
  95. const SizedBox(width: 14),
  96. /// 文字
  97. Expanded(
  98. child: Container(
  99. width: double.infinity,
  100. height: 15,
  101. alignment: Alignment.centerLeft,
  102. // color: Colors.yellowAccent,
  103. child: MarqueeWidget(
  104. model?.listStyle?.length ?? 0,
  105. (BuildContext context, int index) {
  106. NoticeListStyle item = model.listStyle[index];
  107. return Align(alignment: Alignment.centerLeft, child: Text('${item?.contentText}', style: TextStyle(color: HexColor.fromHex(model?.textColor), fontSize: 12)));
  108. },
  109. onPageChanged: (index) => pageIndex = index,
  110. ),
  111. ),
  112. ),
  113. const SizedBox(width: 14),
  114. /// 图片
  115. CachedNetworkImage(imageUrl: model?.jumpImg ?? '', height: 18),
  116. // Container(
  117. // width: 18,
  118. // height: 18,
  119. // color: Colors.red,
  120. // ),
  121. ],
  122. ),
  123. );
  124. }
  125. }
  126. // 上下滚动的消息轮播
  127. class MarqueeWidget extends StatefulWidget {
  128. int count; // 子视图数量
  129. IndexedWidgetBuilder itemBuilder; // 子视图构造器
  130. final ValueChanged<int> onPageChanged;
  131. MarqueeWidget(this.count, this.itemBuilder, {this.onPageChanged});
  132. @override
  133. _MarqueeWidgetState createState() => _MarqueeWidgetState();
  134. }
  135. class _MarqueeWidgetState extends State<MarqueeWidget> {
  136. PageController _controller;
  137. Timer _timer;
  138. @override
  139. void initState() {
  140. super.initState();
  141. if (widget.count > 0) {
  142. _controller = PageController();
  143. _timer = Timer.periodic(Duration(seconds: 5), (timer) {
  144. // 如果当前位于最后一页,则直接跳转到第一页,两者内容相同,跳转时视觉上无感知
  145. if (_controller.page.round() >= widget.count) {
  146. _controller.jumpToPage(0);
  147. }
  148. _controller.nextPage(duration: Duration(seconds: 1), curve: Curves.linear);
  149. });
  150. }
  151. }
  152. @override
  153. Widget build(BuildContext context) {
  154. // return PageView.builder(
  155. // scrollDirection: Axis.vertical,
  156. // controller: _controller,
  157. // itemBuilder: (buildContext, index) {
  158. // if (index < widget.count) {
  159. // return widget.itemBuilder(buildContext, index);
  160. // } else {
  161. // return widget.itemBuilder(buildContext, 0);
  162. // }
  163. // },
  164. // itemCount: widget.count + 1, // 在原数据末尾添加一笔数据(即第一笔数据),用于实现无限循环滚动效果
  165. // );
  166. // }
  167. return PageView.custom(
  168. physics: NeverScrollableScrollPhysics(),
  169. childrenDelegate: SliverChildBuilderDelegate((context, index) {
  170. if (index < widget.count) {
  171. return widget.itemBuilder(context, index);
  172. } else {
  173. return widget.itemBuilder(context, 0);
  174. }
  175. }, childCount: widget.count + 1),
  176. scrollDirection: Axis.vertical,
  177. controller: _controller,
  178. onPageChanged: widget?.onPageChanged,
  179. );
  180. }
  181. @override
  182. void dispose() {
  183. super.dispose();
  184. _controller?.dispose();
  185. _timer?.cancel();
  186. }
  187. }