Flutter TolyUI 框架#02 | Popover 与 Tooltip 设计

发布于:2024-05-10 ⋅ 阅读:(31) ⋅ 点赞:(0)

theme: cyanosis

本文为稀土掘金技术社区首发签约文章,30天内禁止转载,30天后未获授权禁止转载,侵权必究!


《Flutter TolyUI 框架》系列前言:

TolyUI张风捷特烈 打造的 Fluter 全平台应用开发 UI 框架。具备 全平台组件化源码开放响应式 四大特点。可以帮助开发者迅速构建具有响应式全平台应用软件:

开源地址: https://github.com/TolyFx/toly_ui

image.png

该系列将详细介绍 TolyUI 框架使用方式、框架开发过程中的技术知识、设计理念、难题解决等。本篇将介绍 TolyUI 反馈模块 中的两个重要组件,它们的视图职能如下视频所示:

jvideo


一、Tooltip 的再设计

TolyUI 框架中组件的设计原则之一是:

不轻易增加组件,每个 TolyUI 中被设计的组件,都应有它的设计动机。

组件的设计动机包括:

  • [1]. 提供 Flutter 中不存在的常用交互组件。
  • [2]. 对于 Flutter 已有但支持比较弱的组件, TolyUI 将基于源码,进行改造,以此拓展功能。

1.Tooltip 设计动机

Flutter 虽然内置了 Tooltip 组件,但它只能进行简单展示提示信息,效果如下:

03.gif

这种视觉效果并不能满足通用场景:比如提示框的对齐方式,或者气泡包裹自适应边界灵活自定义内容 等。这就是Tooltip 在 TolyUI 中再设计动机,如下通过 TolyTooltip 组件达到的效果:

无标题项目.gif


2. tolyui_feedback 模块

TolyUI 的模块化,将相对独立的功能 单独分包。功能上 Tooltip 在一个组件基础上,展开提示信息。属于一种交互的反馈,反馈内容是静态信息,不参与交互。反馈相关的组件将分离 【tolyui_feedback】 包提供功能:

image.png

同样,使用者可以 tolyui_feedback 独立模块包,或者使用 tolyui 全家桶来享用 TolyTooltip 组件。

```yaml

仅使用反馈模块

dependencies: tolyuifeedback: ^lastversion

使用 tolyui 全家桶

dependencies: tolyui: ^last_version ```


3. TolyTooltip 的功能

Tooltip在的设计语义是: 具有辅助反馈的功能 提示浮层。它会在目标组件 child 为基础,弹出用于展示的文字浮窗。这种浮窗是非侵扰性,一般不会响应事件,也不会消费目标组件的点击事件。在鼠标悬浮/手势长按事件中动画展开浮层。

| 有道 | 飞书 | | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | image.png | image.png |

  • [1]. 动画展示/隐藏浮层弹框。
  • [2]. 支持 12 种弹框与目标组件的对齐方式。
  • [3]. 支持气泡框和非气泡框,填充与边模式线的弹框。
  • [4]. 支持边界溢出检测,并自动适应偏移功能。

二 、TolyTooltip 用法

对于桌面端和 web 平台来说,悬浮展示提示信息是一个非常常用的功能。下面介绍一下 TolyTooltip 的用法,感受一下它所带来的便利性和强大功能。

image.png

TolyTooltip 的使用案例介绍可以网站访问 TolyUI 的 web 版 Flutter 应用。

组件/反馈组件/popover: http://toly1994.com/ui/#/widgets/feedback/tooltip


1. 浮窗的对齐方式

如下所示,TolyTooltip 提供了 12 种浮窗对齐方式,分为上下左右四组,每组有三种对齐方式。另外,默认提示框 支持气泡框,而且气泡的尖角位置会随着对其方式发生变化:

11.gif

使用方式非常简单,直接通过 TolyTooltip 组件嵌套在目标组件之上即可。其中:

  • textStyle 参数可以指定浮窗内文字样式。
  • padding 参数设置浮层弹框内边距。
  • placement 参数设置浮层弹框和目标组件的对其方式。
  • gap 参数设置浮层弹框和目标组件的距离。
  • message 参数设置浮层弹框文字内容。

dart TolyTooltip( textStyle: TextStyle(fontSize: 13,color: Colors.white), padding: EdgeInsets.symmetric(horizontal: 12,vertical: 8), placement: TooltipPlacement.bottom, gap: 12, message: /// 提示信息, child: ///目标组件 ),

提示框摆放的位置,通过 TooltipPlacement 枚举表示。有如下 12 种:

dart enum TooltipPlacement { top, topStart, topEnd, bottom, bottomStart, bottomEnd, left, leftStart, leftEnd, right, rightStart, rightEnd }


2. 展示富文本

可以通过 richText 参数设置 InlineSpan 可以展示富文本。包括使用 WidgetSpan 在文字中嵌入组件。效果如下: :如果不知道 InlineSpan 是什么,可以阅读 《RichText》 组件的相关文章。

无标题项目.gif

```dart const InlineSpan span = TextSpan(children: [ TextSpan(text: '请通过此邮箱联系我们\n '), TextSpan( style: TextStyle(color: Colors.blue), text: '1981462002@qq.com ', ) ]);

TolyTooltip( richMessage: span, placement: TooltipPlacement.top, padding: EdgeInsets.symmetric(horizontal: 12, vertical: 8), gap: 12, child: ///目标组件 ); ```


3. 边界溢出自适应

边界溢出检测,并自动适应偏移功能,是花费我很大心力实现的。相比于绝对遵从对其方式而是提示框溢出边界,只能展示一部分,边界溢出自适应更加合理。如下所示:

  • Flutter 介绍 按钮的 Tooltip 对齐方式设置为 top,但当上方展示的区域不足时,自动转换为 bottom。
  • TolyUI 链接对齐方式设置为 left ,当上方展示的区域不足时,自动转换为 leftStart。

06.gif


4. 样式设置

TolyTooltip 提供了很多可配置的选项,比如背景色、填充模式等,让使用者可以更灵活地展示信息。另外通过设置最大高度,可以在弹框高度过高时允许滑动。效果如下:

07.gif

上面的第一个案例是取消气泡框效果: 将 decorationConfig 参数的 isBubble 置为 false 即可。另外,该配置参数中还可以设置背景色、填充模式、文字颜色:

image.png

dart Widget buildTooltipDisplay1(){ String message = '...'; return TolyTooltip( message: message, placement: TooltipPlacement.top, textStyle: const TextStyle(fontFamily: '宋体',fontSize: 12,fontWeight: FontWeight.bold), decorationConfig: const DecorationConfig( isBubble: false, textColor: Colors.white, ), maxWidth: 250, padding: EdgeInsets.symmetric(horizontal: 16, vertical: 12), gap: 12, child: const TolyLink( text: '张风捷特烈', href: 'https://juejin.cn/user/149189281194766', onTap: jumpUrl, ), ); }


三、Popover 的设计动机

当点击组件时,有时需要打开一个浮层弹框,并且在面板中进行交互。虽然 PopMenuButton 等组件可以展开浮层菜单栏,但是一方面浮层弹框的自定义灵活性很差,另一方面,仅展示一个浮层面板,并不是很符合菜单的语义。\ 比如下面微信和飞书中展开的面板,严格意义上来说不能称之为 菜单,但也不是提示信息。这就是 Popover 的设计动机:

通过交互,展开一个 支持交互 的浮层面板,并允许外界控制展示和隐藏

| 微信头像点击 | 飞书文档 | | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | image.png | image.png |


可能有人会觉得 Tooltip 和 Popover 在功能上差不多。但它们在界面交互中 行使的职能 是有区别的。Tooltip 浮层弹框 只在于展示信息,目标组件的依旧可以形式自己的点击事件。比如AndroidStudio 中鼠标悬浮文件名时,展示详细的路径信息,属于 Tooltip 功能:

image.png

而 Popover 会可能会消耗目标组件的点击事件,弹出浮层弹框;另外该浮层 可以有消费事件 的需求。这两点是它和 Tooltip 的差异所在。比如 Photoshop 工具悬浮时展示的浮层面板,可以通过 Popover 展示:

image.png


四、Popover 的使用

Popover 的使用案例介绍可以网站访问 TolyUI 的 web 版 Flutter 应用。

组件/反馈组件/popover: http://toly1994.com/ui/#/widgets/feedback/popover


1. TolyPopover 的基本使用

TolyPopover 通过 overlay 属性展示浮层面板;builder 方法可以回调控制器,控制器可以主动打开或关闭浮层。如下所示:

08.gif

左侧案例通过 MouseRegion 监听鼠标进入事件,通过控制器打开浮层:

dart TolyPopover( placement: Placement.top, maxWidth: 200, overlay: const DisplayPanel(), builder: (_, ctrl, __) { return MouseRegion( onEnter: (_)=> ctrl.open(), child: const DebugDisplayButton( info: 'Hover Me'), ); }, );

中间的案例通过按钮的点击回调事件 onPressed 方法,通过控制器打开浮层:

dart TolyPopover( placement: Placement.top, maxWidth: 200, overlay: const DisplayPanel(), builder: (_, ctrl, __) { return DebugDisplayButton( info: 'Click Me', onPressed: ctrl.open); }, );

右侧的案例通过 GestureDetector 的长按回调事件 onLongPress 方法,通过控制器打开浮层。除此之外,双击事件,按下事件、抬起事件,甚至是自定义的交互手势,都可以通过控制器来打开或关闭浮层:

dart TolyPopover( placement: Placement.top, maxWidth: 200, overlay: const DisplayPanel(), builder: (_, ctrl, __) { return GestureDetector( onLongPress: ctrl.open, child: const Text('LongPress Me')); }, );


2. 浮层弹框中控制关闭

有时需要在浮层中控制浮层自身的关闭,而关闭浮层的关键在于控制器。也就是说,只要让浮层弹框感知到控制器,即可进行操作。此时可以将 overlay 入参升级为 overlayBuilder,来感知控制器:

09.gif

左侧案例的删除弹框,点击确定或取消后关闭浮层面板。弹框的内容由 DeletePanel 构建,将动画控制器传入其中即可,在点击按键时通过 ctrl 关闭浮层:

image.png

dart TolyPopover( placement: Placement.top, maxWidth: 200, overlayBuilder: (_,ctrl) => DeletePanel( ctrl: ctrl), builder: (_, ctrl, __) { return DebugDisplayButton( info: 'Delete', onPressed: ctrl.open, ); }, );

右侧案例的添加按钮打开菜单也是类似,通过 DisplayMenu 展示菜单内容,构造时传入控制器。另外,和 TolytTooltip 一样,也可以通过 decorationConfig 来配置气泡框的装饰效果:

dart TolyPopover( placement: Placement.bottomEnd, maxWidth: 180, overlayBuilder: (_, ctrl) => DisplayMenu(ctrl), decorationConfig: const DecorationConfig(), builder: (_, ctrl, __) { return GestureDetector( onTap: ctrl.open, child: const Padding( padding: EdgeInsets.symmetric(horizontal: 4.0), child: Icon(Icons.add_circle_outline, color: Color(0xff666666)), ), ); }, );


3. 自定义装饰和偏移

如下所示 TolyPopover 可以给使用者足够的发挥空间,来自定义面板内容以及装饰样式。其中通过 overlayDecorationBuilder 函数构造展示,目的是回调 PopoverDecoration 提供一些必要的参数,你可以根据它来更好的自定义装饰。offsetCalculator 也是如此,可以实现如下效果:

11.gif

左侧案例中,点击头像时展示面板信息。通过 overlayDecorationBuilder 自定义非气泡框的普通装饰;并通过 offsetCalculator 计算偏移量,让弹框左上角和头像的中心对齐:

dart TolyPopover( placement: Placement.rightStart, maxWidth: 260, overlay: const _DisplayPanel(), overlayDecorationBuilder: decorationBuilder, offsetCalculator: calculatorOffset, builder: (_, ctrl, __) { return GestureDetector( onTap: ctrl.open, child: const CircleAvatar( backgroundImage: AssetImage('assets/images/icon_head.webp'), ), ); }, );

calculatorOffset 负责基于 Calculator 数据计算偏移量。它承载着目标组件尺寸、间隔、对齐方式、浮框尺寸四个数据。这里向下移动目标组件尺寸高度的一半,向左移动间隔加上目标组件尺寸宽度一半,即可让浮层左上角和目标组件中心对齐:

dart 计算偏移 Offset calculatorOffset(Calculator calculator){ double x = calculator.boxSize.width / 2 + calculator.gap; double y = calculator.boxSize.height / 2; return Offset(-x, y); }

decorationBuilder 负责自定义装饰,PopoverDecoration 会回调组件尺寸、对齐方式、气泡偏移量三个值。如果你需要自己定义气泡装饰,这些数据将会非常有用。不过这里使用的是普通的 BoxDecoration ,这些数据就没有什么作用了。

dart /// 自定义装饰 Decoration decorationBuilder(PopoverDecoration decoration){ return BoxDecoration( color: Colors.white, border: Border.all(color: Colors.black.withOpacity(0.1)), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.1), offset: const Offset(0, 2), blurRadius: 6, spreadRadius: 0, ) ], borderRadius: BorderRadius.circular(4), ); }


4. Popover 的 对齐方式

Popover 的 12 种浮窗对齐方式和 TolyTooltip 一样;另外指定的对齐方式在溢出边界后也可以自适应转变:

10.gif

dart TolyPopover( maxWidth: 200, placement: Placement.bottom, /// 指定对齐方式 gap: 12, overlay: _DisplayPanel(title: info,), builder: (_,ctrl,__)=> DebugDisplayButton(info: buttonText ,onPressed: ctrl.open,), ),


尾声

这就是 TolyUI 带来的反馈组件的第一波,也是继响应式布局之后,推出的第二个模块。随着 tolyui 的逐步迭代,越来越多的新功能将会支持。感谢你关注 tolyui 的成长,如果喜欢,也希望你能在 github 中点赞支持\~

github 开源地址: https://github.com/TolyFx/toly_ui\ TolyUI 官方案例演示网站:http://toly1994.com/ui

image.png

TolyUI 的下一步会继续设计打造反馈组件,更多的精彩内容,敬请期待 \~


网站公告

今日签到

点亮在社区的每一天
去签到