当前位置:   article > 正文

Flutter 自定义组件-CustomMultiChildLayout_flutter custommultichildlayout

flutter custommultichildlayout

组件构造

  1. CustomMultiChildLayout(
  2. children: [LayoutId(child:Container(),id:"yourId") ],
  3. delegate: _delegate,
  4. )

1. 构造参数介绍

  1. children:组件列表,需要使用LayoutId进行嵌套

  2. delegate:代理类需自定义delegate实现MultiChildLayoutDelegate

2. LayoutId构造参数介绍

  1. child:子组件,真正显示组件

  2. id:组件对应id,不可重复,object类型

代理类实现

  1. class TestDelegate extends MultiChildLayoutDelegate{
  2. @override
  3. void performLayout(Size size) {
  4. // TODO: implement performLayout
  5. }
  6. @override
  7. bool shouldRelayout(covariant MultiChildLayoutDelegate oldDelegate) {
  8. // TODO: implement shouldRelayout
  9. throw UnimplementedError();
  10. }
  11. }

1. 方法介绍

  1. performLayout:页面组件绘制过程,在此方法中绘制组件

  2. shouldRelayout:是否重绘

2. performLayout内部实现

  1. idList.forEach((element) { //循环数据列表
  2. if (hasChild(element)) {
  3. Size viewSize =
  4. layoutChild(element, BoxConstraints(maxWidth: size.width)); //获取对应view尺寸,每个,注意BoxConstraints 需要注意如何计算尺寸
  5. if (x + viewSize.width > size.width) {
  6. line += 1;
  7. x = 0;
  8. y += change + runSpacing;
  9. change = 0;
  10. }
  11. positionChild(element, Offset(x, y));//根据坐标值绘制view,如果不调用,同样会绘制只是绘制在0,0位置
  12. x += viewSize.width + spacing;
  13. if (change < viewSize.height) {
  14. change = viewSize.height;
  15. }
  16. lastHeight = viewSize.height;
  17. }
  18. });

 

注意

  1. layoutChild 每个id 只能调用一次

    错误示范:

    1. double height = layoutChild(element, BoxConstraints(maxWidth: size.width)).height;
    2. double width= layoutChild(element, BoxConstraints(maxWidth: size.width)).width;

    正确代码:

    1. double height = 0.0;
    2. double width = 0.0;
    3. Size size = layoutChild(element, BoxConstraints(maxWidth: size.width));
    4. height = size.height;
    5. width = size.width;

     

  2. 除非固定格式否则必须调用positionChild对子view 位置进行绘制

  3. performLayout方法只是操作id

组件注意

CustomMultiChildLayout 是一个无法自动测量内部组件尺寸的布局,组件大小需要外部传入,所以如果当组件直接放入可滑动组件会导致布局高度报错,本人解决方式是曲线救国,如果您有什么好的解决办法也请提出哦(联系方式QQ:243280864)

具有限行的wrap组件

  1. ``
  2. import 'package:flutter/cupertino.dart';
  3. import 'package:flutter/material.dart';
  4. import 'package:flutter/scheduler.dart';
  5. import 'package:zefyr/zefyr.dart';
  6. /**
  7. *
  8. @ProjectName: jiakeapp_live
  9. @ClassName: max_line_wrap
  10. @Description: dart文件描述
  11. @Author: 孙浩
  12. @QQ: 243280864
  13. @CreateDate: 2020/10/13 13:32
  14. */
  15. ///外部暴露组件
  16. class MaxLineWrap extends StatefulWidget {
  17. final List<Widget> children;
  18. final int maxLine;
  19. Widget expandedWidget;
  20. double horizontalSpacing = 0.0;
  21. double verticalSpacing = 0.0;
  22. Widget closeWidget;
  23. MaxLineWrap({
  24. @required this.children,
  25. @required this.maxLine,
  26. @required this.closeWidget,
  27. @required this.expandedWidget,
  28. this.verticalSpacing = 0.0,
  29. this.horizontalSpacing = 0.0,
  30. });
  31. @override
  32. _MaxLineWrapState createState() => _MaxLineWrapState();
  33. }
  34. ///state实现类
  35. class _MaxLineWrapState extends State<MaxLineWrap> {
  36. bool isExpanded = false;
  37. List<int> indexList = [];
  38. double height = 0.0;
  39. _MaxLineWrapDelegate _delegate;
  40. @override
  41. void initState() {
  42. super.initState();
  43. // widget.children.add(widget.moreWidget);
  44. for (int i = 0; i <= widget.children.length; i++) {
  45. indexList.add(i);
  46. }
  47. }
  48. @override
  49. Widget build(BuildContext context) {
  50. _delegate = _MaxLineWrapDelegate(indexList, widget.maxLine, widget.horizontalSpacing,
  51. widget.verticalSpacing, isExpanded, (height) {});
  52. return Container(
  53. child: _WrapLess(
  54. _delegate,
  55. indexList,
  56. isExpanded ? widget.closeWidget : widget.expandedWidget,
  57. widget.children, (timeStamp) {
  58. if (this.height != _delegate.getHeight()) {
  59. height = _delegate.getHeight();
  60. setState(() {});
  61. }
  62. }, () {
  63. setState(() {
  64. isExpanded = !isExpanded;
  65. });
  66. }),
  67. height: height,
  68. );
  69. }
  70. }
  71. ///曲线救国获取高度抽取组件
  72. class _WrapLess extends StatelessWidget {
  73. final _MaxLineWrapDelegate _delegate;
  74. final List<int> indexList;
  75. final List<Widget> viewList;
  76. final Widget lastView;
  77. final GestureTapCallback clickCallBack;
  78. final FrameCallback callback;
  79. _WrapLess(this._delegate, this.indexList, this.lastView, this.viewList,
  80. this.callback, this.clickCallBack) {
  81. WidgetsBinding.instance.addPostFrameCallback(callback);
  82. }
  83. @override
  84. Widget build(BuildContext context) {
  85. return CustomMultiChildLayout(
  86. children: indexList
  87. .map((e) => LayoutId(
  88. child: e != indexList.last
  89. ? viewList[e]
  90. : GestureDetector(
  91. child: lastView,
  92. onTap: clickCallBack,
  93. ),
  94. id: e,
  95. ))
  96. .toList(),
  97. delegate: _delegate,
  98. );
  99. }
  100. }
  101. class _MaxLineWrapDelegate extends MultiChildLayoutDelegate {
  102. final List<int> idList;
  103. final int maxLine;
  104. final double spacing;
  105. final double runSpacing;
  106. final bool isExpanded;
  107. final ValueChanged<double> heightChange;
  108. double viewHeight = 0.0;
  109. int line = 1;
  110. double lineWidth = 0;
  111. bool canDraw = true;
  112. _MaxLineWrapDelegate(this.idList, this.maxLine, this.spacing, this.runSpacing,
  113. this.isExpanded, this.heightChange);
  114. @override
  115. void performLayout(Size size) {
  116. double x = 0.0;
  117. double y = 0.0;
  118. double change = 0;
  119. double lastHeight = 0;
  120. if (!isExpanded) {
  121. Size lastSize =
  122. layoutChild(idList.last, BoxConstraints(maxWidth: size.width));
  123. idList.forEach((element) {
  124. if (hasChild(element) && element != idList.last) {
  125. Size viewSize =
  126. layoutChild(element, BoxConstraints(maxWidth: size.width));
  127. if (line != maxLine) {
  128. if (x + viewSize.width > size.width) {
  129. line += 1;
  130. x = 0;
  131. y += change + runSpacing;
  132. change = 0;
  133. }
  134. } else {
  135. if (x + viewSize.width + spacing + lastSize.width >= size.width &&
  136. !isExpanded) {
  137. // if (maxLine < line) {
  138. canDraw = false;
  139. // }
  140. lastHeight = lastSize.height;
  141. }
  142. }
  143. if (canDraw) {
  144. positionChild(element, Offset(x, y));
  145. x += viewSize.width + spacing;
  146. if (change < viewSize.height) {
  147. change = viewSize.height;
  148. lastHeight = viewSize.height;
  149. }
  150. } else {
  151. positionChild(element, Offset(-1000, -1000));
  152. }}
  153. });
  154. if(!canDraw){
  155. positionChild(idList.last, Offset(x, y));
  156. }else{
  157. positionChild(idList.last, Offset(-1000, -1000));
  158. }
  159. } else {
  160. idList.forEach((element) {
  161. if (hasChild(element)) {
  162. Size viewSize =
  163. layoutChild(element, BoxConstraints(maxWidth: size.width));
  164. if (x + viewSize.width > size.width) {
  165. line += 1;
  166. x = 0;
  167. y += change + runSpacing;
  168. change = 0;
  169. }
  170. positionChild(element, Offset(x, y));
  171. x += viewSize.width + spacing;
  172. if (change < viewSize.height) {
  173. change = viewSize.height;
  174. }
  175. lastHeight = viewSize.height;
  176. }
  177. });
  178. }
  179. viewHeight = y + lastHeight;
  180. }
  181. double getHeight() => viewHeight;
  182. void changeLine() {
  183. line += 1;
  184. lineWidth = 0;
  185. }
  186. @override
  187. bool shouldRelayout(covariant MultiChildLayoutDelegate oldDelegate) {
  188. return false;
  189. }
  190. }

外部使用

  1. MaxLineWrap(
  2. children: short.data.classList
  3. .map((e) => buildWrapItem(e, short))
  4. .toList(),
  5. maxLine: 3,
  6. horizontalSpacing: W(20),
  7. verticalSpacing: W(16),
  8. closeWidget: buildLabelBtnWidget(
  9. "收起", Res.label_down),
  10. expandedWidget: buildLabelBtnWidget(
  11. "更多", Res.label_down))

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/307835
推荐阅读
相关标签
  

闽ICP备14008679号