theme: cyanosis
FlutterUnit 基于 TolyUI 大大简化了界面构建的代码复杂程度,因此之前想要实现的一些小功能,就可以轻松支持。布局游乐场是通过交互的方式来 直观体验 组件的布局特性,从而更易学和掌握。目前 FlutterUnit 已在 知识集录模块新增了 布局宝库, 大家可以更新代码查看 ~
1. 什么是布局游乐场
对于新手朋友,对有些较复杂的布局组件很难把握其特性。为此 FlutterUnit 设立了 布局宝库 模块,来帮助开发者更容易理解 Flutter 中的布局特性以及核心的布局组件。其中的 Playground 指的是可交互操作的组件展示面板,如下的 Flex Playground 将淋漓尽致地展示 Flex 组件布局特性。
Playground 实现过程中,依赖了很多 TolyUI 中的组件:
- 对于枚举类型的参数,通过 TolySelect 组件处理选择事件。
- 操作的图标按钮使用 TolyAction 组件。
- 布局宝库的侧栏导航,使用 TolyRailMenuTree 组件。
目前已经完成了 Flex、Wrap、Stack 三个多字布局的 Playground 。可以在操作面板中增加/删除,指定宽高的色块。来更好的体验组件的布局效果。
2. Flex Playground 功能实现 - 数据层
下面以 Flex Playground 来介绍一下功能实现。一个 Playground 主要包括两个区域:左侧的组件 效果展示区 和右侧的 操作面板区。其中右侧的交互操作会影响左侧的效果展示:
我们知道 Flutter 中,数据决定界面的表现,首先应该确定 Flex Playground 中依赖了哪些数据。当前功能是通过交互修改 Flex 组件的属性,所以 Flex 组件的属性内容是一份需要维护的状态。通过下面的 FlexAttr 类承载各个属性数据:
dart class FlexAttr { final Axis direction; final MainAxisAlignment mainAxisAlignment; final CrossAxisAlignment crossAxisAlignment; final MainAxisSize mainAxisSize; final TextDirection textDirection; final VerticalDirection verticalDirection; final TextBaseline textBaseline;
另外,需要若干个色块,它们有各自的宽度和高度,通过 DisplayItem 类承载相关数据:
dart class DisplayItem { final double width; final double height; final Color color;
这样 Flex Playground 中的状态数据就呼之欲出了:
[1]
. DisplayItem 列表数据,记录色块信息。[2]
._selectIndex
选中的色块索引,用于删除色块。[3]
. FlexAttr 数据,决定 Flex 组件的展示效果。
dart class _FlexPlaygroundState extends State<FlexPlayground> { List<DisplayItem> _data = []; late FlexAttr _attr; int _selectIndex = -1;
3. Flex Playground 功能实现 - 视图层
左侧的布局效果展示区封装为如下的 FlexDisplay 组件,依赖三个状态数据,通过 Flex 组件来构建展示内容。其中,
- Flex 构造函数中的各个属性由 FlexAttr 数据提供;
children
组件由List<DisplayItem>
数据映射得到;- 色块的选中事件,通过
onSelectChanged
回调,交由使用者处理,更新激活索引。
```dart class FlexDisplay extends StatelessWidget { final List items; final FlexAttr attr; final int selectIndex; final ValueChanged onSelectChanged;
const FlexDisplay({ super.key, required this.items, required this.attr, required this.selectIndex, required this.onSelectChanged, });
@override Widget build(BuildContext context) { return Flex( direction: attr.direction, mainAxisAlignment: attr.mainAxisAlignment, crossAxisAlignment: attr.crossAxisAlignment, mainAxisSize: attr.mainAxisSize, textDirection: attr.textDirection, verticalDirection: attr.verticalDirection, textBaseline: TextBaseline.alphabetic, children: items.asMap().keys.map((int index) { bool active = selectIndex == index; return GestureDetector( onTap: () => onSelectChanged(index), child: DisplayPlayItem(item: items[index], selected: active), ); }).toList(), ); } } ```
右侧的操作面板需要支持交互操作,通过触发事件来更新状态数据,然后更新界面,即可实现我们期望的功能。Flex 组件的属性中有很多枚举值,这比较适合使用下拉选择来处理。Flutter 中自带的选择器在桌面端的体验效果并不是很好,于是 TolyUI 中提供了 TolySelect 组件,便于构建类似的选择功能:
右侧的面板通过 FlexOpTool 组件展示,其中添加、删除、重置的按钮事件,分别通过回调交由使用者处理。另外属性操作时数据的变化,也会通过 ValueChanged
通知外界进行数据处理。也就是说 FlexOpTool 本身并不参与状态数据的维护逻辑。只负责基于数据构建界面,以及数据变化时的回调通知:
dart class FlexOpTool extends StatefulWidget { final ValueChanged<Size> onAddBox; final VoidCallback onDelete; final VoidCallback onReset; final FlexAttr attr; final ValueChanged<FlexAttr> onAttrChange;
这里着重介绍一下选择器的使用, TolySelect 主要通过 String 列表 data
和激活索引 selectIndex
决定菜单项羽和激活项;通过 cellStyle
可以简单定制菜单项的展示效果。由于这里选择器的使用场合非常多,所以封装了 ItemSelector
组件统一处理标题、布局等效果:
```dart typedef NameCalc = String Function(T data);
class ItemSelector extends StatelessWidget { final int selectIndex; final List data; final NameCalc calcFun; final ValueChanged onSelect; final String label; final String subTitle;
const ItemSelector({ super.key, required this.selectIndex, required this.data, required this.calcFun, required this.onSelect, required this.subTitle, required this.label, });
@override Widget build(BuildContext context) { TextStyle labelStyle = const TextStyle(color: Color(0xff61666d), fontSize: 12); DropMenuCellStyle lightStyle = const DropMenuCellStyle( padding: EdgeInsets.symmetric(horizontal: 4,vertical: 1), borderRadius: BorderRadius.all(Radius.circular(6)), foregroundColor: Color(0xff1f1f1f), backgroundColor: Colors.transparent, disableColor: Color(0xffbfbfbf), hoverBackgroundColor: Color(0xfff5f5f5), hoverForegroundColor: Color(0xff1f1f1f), textStyle: TextStyle(fontSize: 11) ); return Padding( padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 6), child: Row( children: [ Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(label, style: labelStyle), Text(subTitle, style: labelStyle.copyWith(fontSize: 8)), ], ), const Spacer(), TolySelect( fontSize: 11, cellStyle: lightStyle, data: data.map((e) => calcFun(e)).toList(), selectIndex: selectIndex, iconSize: 16, height: 25, width: 110, maxHeight: 200, onSelected: (int index) => onSelect(data[index]), ) ], ), ); } } ```
4. Flex Playground 功能实现 - 数据逻辑层
FlexOpTool 提供了交互过程中数据变化的时机,使用者需要在对应的时机来维护状态数据的正确性。
如下所示,_onAddBox
方法,会在 DisplayItem
列表中增加一个色块,触发 setState 重新构建;_deleteSelectIndex
方法将移除对应索引的色块,并重新构建更新界面:
```dart void _onAddBox(Size size) { int index = _data.length + 1; Color color = kColors[index % kColors.length]; _data.add(DisplayItem(width: size.width, height: size.height, color: color)); setState(() {}); }
void deleteSelectIndex() { if (selectIndex < 0 || selectIndex >= _data.length) { $message.warning(message: '请先选择删除的色块!'); return; } _data.removeAt(selectIndex); _selectIndex = -1; setState(() {}); } ```
当属性数据变化,通过 _onAttrChange
方法更新 _attr
数据即可;重置回调时,将三个状态数据设为初始值:
```dart void _onAttrChange(FlexAttr attr) { setState(() { _attr = attr; }); }
void _reset({bool init=false}){ _attr = FlexAttr(direction: Axis.horizontal); _data = [ DisplayItem(width: 20, height: 20, color: kColors[0]), DisplayItem(width: 10, height: 80, color: kColors[1]), DisplayItem(width: 40, height: 30, color: kColors[2]), DisplayItem(width: 60, height: 20, color: kColors[3]), ]; _selectIndex = -1; if(init) return; setState(() {}); } ```
这就是 Flex Playground 功能的核心实现过程,紧紧把握 状态数据
、组件构建
、交互事件
和 数据维护
四个方面,就可以很轻松地完成任何功能需求。其他的 Playground 实现方式类似,就不一一介绍了,希望大家可以在 布局游乐场 中,通过交互的方式,学习更多知识。
以后,FlutterUnit 将在 TolyUI 的加持下,支持更多的好玩和使用的功能,敬请期待~
本站资源均来自互联网,仅供研究学习,禁止违法使用和商用,产生法律纠纷本站概不负责!如果侵犯了您的权益请与我们联系!
转载请注明出处: 免费源码网-免费的源码资源网站 » FlutterUnit & TolyUI | 布局游乐场
发表评论 取消回复