- 前端
- 跨平台
- 桌面应用
- 移动开发
【免费下载链接】flet
Build realtime web, mobile and desktop apps in Python only. No frontend experience required.
DismissibleUpdateEvent是 Flet 中Dismissible控件在用户拖拽(dismiss 手势)过程中持续触发的事件负载(event payload)。它通过on_update回调向 Python 侧实时上报拖拽方向、进度、是否越过"可撤销删除阈值"等状态,是实现"滑动删除前预览进度、到达阈值给出视觉反馈、跨过阈值后执行删除"等交互的关键数据源。读完本文,你将掌握该事件的全部字段语义、底层触发链路,以及结合dismiss_thresholds与confirm_dismiss的完整实战写法。
事件概述:拖拽过程中实时上报的"进度快照"
DismissibleUpdateEvent定义于 Python 源码 dismissible.py,其类文档明确说明它是在 "a dismiss gesture is in progress"(拖拽手势进行中)时发出的负载。与DismissibleDismissEvent(在确认/完成撤销后触发)不同,DismissibleUpdateEvent的特点是高频、连续:只要用户按住内容进行拖拽,就会持续派发,让应用能够逐帧感知手势状态。
它与Dismissible控件的on_update回调直接绑定:
ft.Dismissible( content=ft.ListTile(title=ft.Text("Item")), on_update=handle_update, # 拖拽过程中持续触发 )从源码结构看,DismissibleUpdateEvent继承自flet.controls.control_event.Event(control_event.py),因此它同样自带name(事件名)、control(触发事件的控件实例)、page(事件所属页面)等通用字段,方便在回调里访问父级控件与页面上下文。
字段详解:direction / progress / reached / previous_reached
DismissibleUpdateEvent共定义 4 个专属字段,全部来自 Flutter 框架Dismissible.onUpdate回调的DismissUpdateDetails参数。逐一定义如下(引用自 dismissible.py):
| 字段 | 类型 | 语义 | 取值范围/说明 |
|---|---|---|---|
direction | DismissDirection | 当前拖拽手势的方向 | 见下文枚举说明 |
progress | float | 拖拽进度 | 相对于撤销阈值的0.0~1.0 |
reached | bool | 当前是否已达到撤销阈值 | True表示本次更新时已越过阈值 |
previous_reached | bool | 上一次更新事件时是否已达到阈值 | 用于检测"刚刚越界"或"刚刚退回"的边沿变化 |
其中progress与reached的组合是最常用的判断依据:progress给出连续进度(可用于驱动背景色渐变、图标缩放等过渡动画),而reached给出离散的布尔状态(决定是否显示"松开即可删除"的提示)。
previous_reached则解决了reached本身无法表达"状态刚刚发生变化"的问题——通过比较reached != previous_reached,应用可以精确捕获"刚刚越过阈值"(reached=True, previous_reached=False)与"刚刚拖回阈值内"(reached=False, previous_reached=True)这两个边沿时刻,从而只在这些瞬间执行一次性的反馈逻辑(如震动、播放音效)。
direction 的取值:DismissDirection 枚举
direction字段的类型DismissDirection是枚举类,定义于 snack_bar.py(与SnackBar共用同一枚举):
NONE:禁用滑动撤销手势;VERTICAL:允许向上或向下滑动撤销;HORIZONTAL:允许向左或向右滑动撤销(Dismissible.dismiss_direction的默认值);END_TO_START:沿"尾端到起始端"阅读方向滑动(LTR 语言即从右往左);START_TO_END:沿"起始端到尾端"阅读方向滑动(LTR 语言即从左往右);UP/DOWN:仅允许向上 / 仅允许向下滑动撤销。
注意END_TO_START与START_TO_END是感知语言方向(locale-aware)的,在从右到左(RTL)语言环境中方向会反转,适合需要国际化适配的列表删除交互。
底层链路:从 Flutter 手势到 Python 事件的完整数据流
DismissibleUpdateEvent的触发链路横跨 Flutter 端与 Python 端,理解它有助于排查"事件不触发"或"字段为 None"等问题:
- Flutter 端:
DismissibleControl构建 Flutter 原生Dismissible控件,并把onUpdate回调绑定为"将DismissUpdateDetails序列化后触发 update 事件"(dismissible.dart); - 序列化:Dart 侧
DismissibleUpdateEvent.toMap()将direction、progress、reached、previous_reached四个字段打包为 JSON(dismissible.dart),其中direction取details.direction.name字符串值; - 传输与反序列化:事件经 Flet 的通信通道送达 Python 侧,由
Dismissible控件的事件处理机制反序列化为flet.DismissibleUpdateEvent实例; - Python 回调:最终调用
on_update绑定的处理函数。
关键点:Dart 端只有在widget.control.hasEventHandler("update")为真时才会绑定onUpdate(dismissible.dart),因此不写on_update回调就不会产生任何 update 事件,这是对性能的有意优化——高频拖拽事件不会在无人监听时白白穿过通信链路。
实战示例:滑动删除列表中的实时进度反馈
仓库示例 dismissible_list_tiles/main.py 完整演示了DismissibleUpdateEvent的接入方式。下面是一个在示例基础上扩展了"阈值边沿检测"的完整可运行代码:
import flet as ft def main(page: ft.Page): def handle_update(e: ft.DismissibleUpdateEvent): # 打印事件负载,观察 direction / progress / reached / previous_reached print(e) # 边沿检测:刚刚越过阈值 if e.reached and not e.previous_reached: print(f"Item 即将被删除:direction={e.direction}, progress={e.progress:.2f}") # 刚刚拖回阈值内 if not e.reached and e.previous_reached: print("已取消删除,拖回原位") # 用 progress 驱动中间态(例如 0~50% 提示"继续滑动") if not e.reached and e.progress > 0.3: print("继续滑动以删除……") def handle_dismiss(e: ft.Event[ft.Dismissible]): # 真正被删除后,从列表移除该行 e.control.parent.controls.remove(e.control) e.control.parent.update() page.add( ft.SafeArea( content=ft.ListView( expand=True, controls=[ ft.Dismissible( dismiss_direction=ft.DismissDirection.HORIZONTAL, background=ft.Container(bgcolor=ft.Colors.GREEN), secondary_background=ft.Container(bgcolor=ft.Colors.RED), on_update=handle_update, on_dismiss=handle_dismiss, dismiss_thresholds={ ft.DismissDirection.END_TO_START: 0.2, ft.DismissDirection.START_TO_END: 0.2, }, content=ft.ListTile(title=ft.Text(f"Item {i}")), ) for i in range(10) ], ), ) ) if __name__ == "__main__": ft.run(main)要点说明:
dismiss_thresholds以字典形式按方向分别设置阈值(取值0.0~1.0之间的小数),即progress达到1.0所对应的拖拽比例。示例中把左右两个方向都设为0.2,意味着内容被拖出自身宽度 20% 即视为"达到阈值";reached与previous_reached正是围绕dismiss_thresholds计算出来的:当前拖拽比例 ≥ 阈值时reached=True,否则为False;- 若未设置
on_dismiss,即使拖过阈值松手,内容也只会弹回原位,不会执行删除——真正删除仍由on_dismiss(或on_confirm_dismiss+confirm_dismiss)负责。
与 on_confirm_dismiss 协同:先预览、后确认
DismissibleUpdateEvent常用于"预览阶段"的反馈,而确认逻辑由Dismissible的另一组回调承担:
on_update:拖拽进行中,实时反馈(本文主题);on_confirm_dismiss:拖拽松手且达到阈值后触发,给应用一个"确认或否决"的机会,此时控件会被锁定无法再次拖拽,直到调用confirm_dismiss(bool)解决挂起的决策(dismissible.py);on_dismiss:内容完成收缩动画、确认撤销后触发。
仓库示例 dismissible_list_tiles/main.py 展示了典型组合:在on_confirm_dismiss中弹出AlertDialog让用户确认,确认后调用e.control.confirm_dismiss(True)完成删除,取消则传False让内容回到原位。在这一流程中,DismissibleUpdateEvent可以提前告知用户"当前拖拽已过阈值,松开将弹出确认框",避免误触。
调试建议
由于 update 事件是高频事件,直接打印事件对象即可快速观察字段变化规律:
def handle_update(e: ft.DismissibleUpdateEvent): print(e) # 观察 direction / progress / reached / previous_reached若事件始终不触发,按以下顺序排查:
- 是否在
Dismissible上绑定了on_update(未绑定则 Dart 端不注册onUpdate,参见 dismissible.dart); - 是否设置了
dismiss_direction且手势方向与之一致(例如仅UP时左右拖拽不会触发 update); - 控件是否可见——
Dismissible.content必须是可见控件(dismissible.py)。
延伸阅读
- 控件完整属性与全部事件:Dismissible 控件文档
- 事件基类(
name/data/control/page字段):Event 类型文档 - 同族事件
DismissibleDismissEvent:与DismissibleUpdateEvent同文件定义(dismissible.py),承载on_confirm_dismiss/on_dismiss的direction信息 - 完整运行示例:dismissible_list_tiles/main.py
- 前端
- 跨平台
- 桌面应用
- 移动开发
【免费下载链接】flet
Build realtime web, mobile and desktop apps in Python only. No frontend experience required.
相关推荐
DINOv2 选型实战:4 种规格怎么选才不踩坑
DINOv2 选型实战:4 种规格怎么选才不踩坑 你要把视觉特征接进分类流水线,翻到 DINOv2 从 ViT S/14 到 ViT g/14 的四种规格时卡住
前端跨平台桌面应用移动开发Flet Charts 交互事件详解:LineChartEvent 的完整字段、事件类型与实战用法
Flet Charts 交互事件详解:LineChartEvent 的完整字段、事件类型与实战用法 LineChartEvent 是 Flet 图表扩展( fl
前端跨平台桌面应用移动开发Flet ContextMenuDismissEvent 事件详解:字段、触发时机与实战用法
Flet ContextMenuDismissEvent 事件详解:字段、触发时机与实战用法 ContextMenuDismissEvent 是 Flet 框架
前端跨平台桌面应用移动开发
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考