Flet 页面尺寸变化事件 PageResizeEvent 完全指南:监听窗口与浏览器尺寸变更,构建响应式布局

原创2026-09-23 12:21:571,427 阅读
文章标签:前端跨平台桌面应用移动开发

Flet 页面尺寸变化事件 PageResizeEvent 完全指南:监听窗口与浏览器尺寸变更,构建响应式布局

PageResizeEvent 是 Flet 中用于在包含应用的窗口(原生桌面/移动窗口)或浏览器视口尺寸发生变化时通知应用的事件对象,其定义与行为可直接在 Flet Python SDK 的 base_page.py 源码中找到完整依据。本文将以该事件为核心,讲解其数据字段、page.on_resize 绑定方式、底层事件分发机制,并结合仓库中的响应式布局示例,给出可直接复制的实战代码,帮助你在 Python 端实时感知页面尺寸并动态调整布局。

PageResizeEvent 是什么:定义与触发时机

PageResizeEvent 是一个继承自 Event["BasePage"] 的 Python dataclass,源码注释明确指出其语义:

Event fired when the size of the containing window or browser is changed. Typically used to adapt layout dynamically in response to resizes, such as switching between compact and expanded views in a responsive design.

翻译成通俗语言就是:当承载 Flet 应用的容器尺寸发生变化时触发,典型场景包括:

  • 桌面端(Windows / macOS / Linux)用户拖拽调整原生窗口大小;
  • Web 端用户缩放浏览器窗口、切换设备方向或改变浏览器侧边栏宽度;
  • 移动端窗口尺寸变化(例如旋转屏幕导致的横竖屏切换)。

它的核心用途是响应式设计——根据尺寸实时切换紧凑布局(compact view)与展开布局(expanded view),或动态调整控件密度、隐藏/显示侧边栏等。注意事件所反映的"页面尺寸"是整个页面(Page)的尺寸,而非某个控件的尺寸,这一点与控件级事件(如滚动事件 OnScrollEvent)有明显区别。

事件携带的数据字段:width 与 height

PageResizeEvent 本身只携带两个数据字段,均通过 dataclass 声明,见 base_page.py:

字段 类型 含义
width float 页面新的宽度,单位为逻辑像素(logical pixels)
height float 页面新的高度,单位为逻辑像素(logical pixels)

"逻辑像素"意味着该值已经经过设备像素比(device pixel ratio)换算,在高 DPI 屏幕(如 Retina 屏)上,事件给出的数值与 Flutter/Flet 布局系统使用的坐标空间一致,可以直接用来与 page.width、page.height 等页面属性做比较或参与布局计算。

除了这两个字段,事件对象还从基类 Event 继承了 control(触发事件的控件引用,即 BasePage 或其子类 Page/MultiView)与 name(事件名称,此处为 "on_resize")等通用属性。这一点由仓库测试 test_events.py 中的 test_page_events 用例验证:通过 from_dict 以 {"control": p, "name": "on_resize", "width": 1, "height": 2} 构造事件后,断言 isinstance(evt, PageResizeEvent) 成立。

如何监听尺寸变化:绑定 page.on_resize

PageResizeEvent 并不单独使用,它是页面属性 on_resize 的事件类型。BasePage(Page 与 MultiView 的公共基类)声明了该属性(见 base_page.py):

on_resize: Optional[EventHandler["PageResizeEvent"]] = None

其 docstring 给出的最简绑定示例为:

import flet as ft

def main(page: ft.Page):
    def handle_page_size(e):
        print("New page size:", page.window.width, page.window_height)

    page.on_resize = handle_page_size

ft.app(main)

注意:回调函数既可以通过 page.on_resize = handler 直接赋值绑定,也可以作为 ft.app(main, on_resize=handler) 的参数传入(Flet 1.0 起 ft.app 支持将页面事件作为关键字参数),二者等价。事件处理器签名接收一个 PageResizeEvent 参数,在事件触发时由 Flet 运行时自动创建并注入。

对于 MultiView 场景同样适用——由于 PageResizeEvent 的类型参数是 BasePage,MultiView 也具备 on_resize 能力,可以让每个多窗口视图独立响应尺寸变化。

类型注解与 IDE 支持:get_event_field_type 机制

Flet 的页面事件(on_resize、on_media_change 等)在类型系统上做了精细区分,而非统一退化为 ControlEvent。仓库测试 test_events.py 的 test_get_page_event_field_type 用例断言:

on_resize_type = get_event_field_type(page, "on_resize")
assert on_resize_type == PageResizeEvent
assert on_resize_type != ControlEvent

这意味着在 IDE 中编写:

def handle_page_resize(e: ft.PageResizeEvent):
    print(e.width, e.height)

可以获得完整的字段补全与类型检查。此外,test_page_forward_ref_resolution_uses_base_module 用例(test_events.py)还验证了类型前向引用(forward reference)的解析机制——即使从 flet.controls.page 模块中移除 PageResizeEvent 符号,类型仍能通过 base_page 基模块正确解析,保证事件类型注解在运行时稳定可靠。

实战示例:结合 ResponsiveRow 的实时响应式布局

仓库自带的官方示例 responsive_row/main.py 是 PageResizeEvent 最典型的应用场景:将当前页面宽度实时显示在界面上,同时配合 ResponsiveRow 在不同断点下自动调整列布局。

import flet as ft

def main(page: ft.Page):
    def handle_page_resize(e: ft.PageResizeEvent):
        pw.value = f"{page.width} px"
        pw.update()

    page.on_resize = handle_page_resize

    pw = ft.Text(text_align=ft.TextAlign.END, style=ft.TextTheme.display_small)

    page.add(
        ft.SafeArea(
            content=ft.Column(
                controls=[
                    ft.ResponsiveRow(
                        controls=[
                            ft.Container(
                                content=ft.Text("Column 1"),
                                padding=5,
                                bgcolor=ft.Colors.YELLOW,
                                col={
                                    ft.ResponsiveRowBreakpoint.XS: 12,
                                    ft.ResponsiveRowBreakpoint.MD: 6,
                                    ft.ResponsiveRowBreakpoint.LG: 3,
                                },
                            ),
                            # ... 更多列
                        ]
                    )
                ]
            )
        )
    )

ft.app(main)

该示例揭示了几个关键实践要点:

  1. 事件参数与页面属性可以互补使用:回调中虽然收到了 e: ft.PageResizeEvent,但取当前宽度时既可以直接读 e.width,也可以读 page.width——二者反映的是同一时刻的页面尺寸。示例选择 page.width 以强调"页面级"属性与事件的一致性。
  2. 回调内必须调用 update():Flet 是声明式即时更新模型,修改 pw.value 后需调用 pw.update() 才会把新文本同步到客户端渲染层;本例将 pw 定义为函数外部的局部变量,通过闭包在回调中修改。
  3. 与 ResponsiveRow 断点协作:ResponsiveRow 本身会根据页面宽度在 XS(12 列全宽)、MD(6 列半宽)、LG(3 列四分之一宽)等断点自动重排,而 PageResizeEvent 负责在尺寸变化的第一时间驱动页面上其他依赖宽度的自定义逻辑(如本例的宽度文本、或自绘 Canvas 缩放、菜单折叠等)。
  4. SafeArea 包裹避免刘海屏遮挡:在移动端窗口尺寸变化(如旋转屏幕)时,安全区会随之改变,用 SafeArea 包裹内容可保证布局始终在安全区域内。

运行方式:将上述代码保存为 main.py,在仓库根目录执行 flet run sdk/python/examples/controls/core/responsive_row/responsive_row/main.py(或直接 python main.py 后由 Flet 启动桌面窗口),拖动窗口边缘即可看到右上角宽度数值实时刷新。

底层原理:事件从客户端到 Python 端的传递

PageResizeEvent 的完整链路可以用下图理解(示意,非仓库原图):

Flutter 客户端(窗口/浏览器尺寸变化)
        │  通过 WebSocket / HTTP 发送事件载荷
        ▼
Flet 服务端运行时(Event 反序列化)
        │  from_dict 依据类型注解构造事件对象
        ▼
PageResizeEvent(width=…, height=…, control=page, name="on_resize")
        │  调用用户注册的 on_resize 回调
        ▼
用户布局调整逻辑(update() 刷新 UI)

仓库测试 test_events.py 中 from_dict 的用法正是这一反序列化过程的缩影:服务端收到 JSON 形式的事件载荷后,通过 get_event_field_type 查找到 on_resize 对应的 PageResizeEvent 类型,再按字段名(width、height)构造出类型化的事件对象。这也是 Flet "Python-only 全栈" 架构在事件层面的体现——所有平台(桌面、Web、移动)的窗口尺寸变化最终都归一化为这一个统一的 Python 事件。

与相关 API 的关系及进阶建议

PageResizeEvent 属于页面级事件体系中的一员,与以下 API 常搭配使用:

  • page.width / page.height:页面当前尺寸的只读属性,在回调之外(如响应 on_mounted)同样可读;
  • page.on_media_change / page.media:媒体数据变化事件(PageMediaData),当设备方向、安全区等媒体特性变化时触发,与窗口尺寸变化经常同时发生(如手机旋转),两者结合可实现完整的响应式适配;
  • page.window(桌面端):Window 对象提供窗口级操作能力,例如 page.window.width 与事件中的 width 在桌面端语义一致;
  • ResponsiveRow / GridView:声明式自适应布局控件,与事件监听形成"框架自动 + 业务自定义"双层响应式方案。

性能提示:窗口拖拽过程中 PageResizeEvent 会高频触发(尤其 Web 端连续缩放时)。回调中应避免执行重计算或高频创建控件,推荐做法是:只更新轻量文本/标志位,将重布局交给 ResponsiveRow 等声明式机制完成;若确有重逻辑,可自行加入防抖(debounce)——例如仅当 e.width 跨越预设断点阈值时才执行切换操作。

小结

  • PageResizeEvent 在包含应用的窗口或浏览器尺寸变化时触发,字段 width、height 以逻辑像素给出新尺寸;
  • 通过 page.on_resize(或 ft.app(on_resize=...))绑定回调,回调可同时使用事件字段与 page.width 页面属性;
  • 类型系统将 on_resize 精确关联到 PageResizeEvent,可享受 IDE 补全与类型检查;
  • 典型实战场景是与 ResponsiveRow 配合实现实时响应式布局,参考仓库示例 responsive_row/main.py;
  • 底层由 Flet 服务端通过 from_dict 反序列化客户端事件载荷生成类型化对象,相关机制有 test_events.py 完整测试保障。

掌握 PageResizeEvent 后,你便能在纯 Python 侧实时感知任何平台上的页面尺寸变化,为构建自适应、可伸缩的 Flet 应用打下基础。

登录后查看全文
flet