FlutterUnit TolyUI | 布局游乐场

news/2024/10/5 22:48:31/

theme: cyanosis

FlutterUnit 基于 TolyUI 大大简化了界面构建的代码复杂程度,因此之前想要实现的一些小功能,就可以轻松支持。布局游乐场是通过交互的方式来 直观体验 组件的布局特性,从而更易学和掌握。目前 FlutterUnit 已在 知识集录模块新增了 布局宝库, 大家可以更新代码查看 ~


1. 什么是布局游乐场

对于新手朋友,对有些较复杂的布局组件很难把握其特性。为此 FlutterUnit 设立了 布局宝库 模块,来帮助开发者更容易理解 Flutter 中的布局特性以及核心的布局组件。其中的 Playground 指的是可交互操作的组件展示面板,如下的 Flex Playground 将淋漓尽致地展示 Flex 组件布局特性。

01.gif

Playground 实现过程中,依赖了很多 TolyUI 中的组件:

  • 对于枚举类型的参数,通过 TolySelect 组件处理选择事件。
  • 操作的图标按钮使用 TolyAction 组件。
  • 布局宝库的侧栏导航,使用 TolyRailMenuTree 组件。

目前已经完成了 Flex、Wrap、Stack 三个多字布局的 Playground 。可以在操作面板中增加/删除,指定宽高的色块。来更好的体验组件的布局效果。


2. Flex Playground 功能实现 - 数据层

下面以 Flex Playground 来介绍一下功能实现。一个 Playground 主要包括两个区域:左侧的组件 效果展示区 和右侧的 操作面板区。其中右侧的交互操作会影响左侧的效果展示:

image.png

我们知道 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 回调,交由使用者处理,更新激活索引。

image.png

```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 组件,便于构建类似的选择功能:

image.png

右侧的面板通过 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 组件统一处理标题、布局等效果:

image.png

```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 提供了交互过程中数据变化的时机,使用者需要在对应的时机来维护状态数据的正确性。

image.png

如下所示,_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 的加持下,支持更多的好玩和使用的功能,敬请期待~


http://www.ppmy.cn/news/1473446.html

相关文章

收银系统源码-营销活动-积分商城

1. 功能描述 营运抽奖&#xff1a;智慧新零售收银系统&#xff0c;线上商城的营销插件&#xff0c;由商户运营&#xff0c;用户通过多种渠道可以获取积分&#xff0c;不仅支持在收银端抵用&#xff0c;还可以在积分商城内兑换优惠券或者真实商品&#xff0c;提升会员活跃度&am…

Spring Boot + liteflow 居然这么好用!实战

在我们的日常开发中&#xff0c;经常会遇到一些需要串行或并行处理的复杂业务流程。 那我们该如何利用Spring Boot结合liteflow规则引擎来简化我们的业务流程 先看一个实战案例&#xff01;&#xff01; 在电商场景下&#xff0c;当订单完成后&#xff0c;我们需要同时进行积…

Ubuntu、CentOs更换源(阿里云的源)

ubuntu 备份当前的apt配置文件 sudo mv /etc/apt/sources.list /etc/apt/sources.list.backup编辑配置文件&#xff0c;将以下内容写到文件中sudo vi /etc/apt/sources.list deb https://mirrors.aliyun.com/ubuntu/ focal main restricted universe multiverse deb-src ht…

SQL窗口函数详解

详细说明在sql中窗口函数是什么&#xff0c;为什么需要窗口函数&#xff0c;有普通的聚合函数了那窗口函数的意义在哪&#xff0c;窗口函数的执行逻辑是什么&#xff0c;over中的字句是如何使用和理解的&#xff08;是不是句句戳到你的痛点&#xff0c;哼哼&#xff5e;&#x…

一文了解常见DNS问题

当企业的DNS出现故障时&#xff0c;为不影响企业的正常运行&#xff0c;团队需要能够快速确定问题的性质和范围。那么有哪些常见的DNS问题呢&#xff1f; 域名解析失败&#xff1a; 当您输入一个域名&#xff0c;但无法获取到与之对应的IP地址&#xff0c;导致无法访问相应的网…

支持离线的稍后阅读工具HamsterBase

什么是 HamsterBase &#xff1f; HamsterBase 是一个以隐私优先的、离线友好的稍后阅读工具。软件本身不需要连接互联网&#xff0c;没有遥测功能&#xff0c;不收集任何私人信息&#xff0c;也不需要登录或注册。同时&#xff0c;HamsterBase 是一个开放的知识管理工具&#…

【Python】基于KMeans的航空公司客户数据聚类分析

&#x1f490;大家好&#xff01;我是码银~&#xff0c;欢迎关注&#x1f490;&#xff1a; CSDN&#xff1a;码银 公众号&#xff1a;码银学编程 实验目的和要求 会用Python创建Kmeans聚类分析模型使用KMeans模型对航空公司客户价值进行聚类分析会对聚类结果进行分析评价 实…

MyBatis(26)MyBatis 有哪些方式可以实现多数据源管理

在企业级应用开发中&#xff0c;有时需要同时操作多个数据库&#xff0c;这就涉及到多数据源管理的问题。MyBatis作为一个流行的持久层框架&#xff0c;本身并没有直接提供多数据源管理的功能&#xff0c;但是可以通过与Spring等框架结合&#xff0c;或者通过自定义方式来实现多…