跳到主要内容

Flet v0.23.0 发布公告

· 阅读需 5 分钟
Henri Ndonko
Flet 贡献者和维护者

我们很高兴地宣布 Flet 0.23.0 的发布。这是一个重大的版本,带来了许多新特性和错误修复。

新控件

新属性

错误处理

PEP 20 (Python 之禅):错误永远不应默默地过去。

一些开发者报告说,在某些情况下,控件可能会在没有明显错误信息的情况下视觉上崩溃。

例如,在问题 #3149 中,@base-13 提到 "在 DataTable 中,如果列数少于任意一行中的数据单元格数,则整个表格将变灰而不抛出错误"

了解这一点,我们在大多数控件中添加了更多的断言检查,以便当您提供错误的值时,会引发一个 AssertionError,带有明确的错误消息。

如果您发现某些检查仍然缺失,请指出来以便我们解决。

命令行(CLI)输出

flet build 命令的输出已经被美化。

此外,添加了一个新的选项 --show-platform-matrix,它显示一个包含构建平台矩阵的表格,该表格的标题列为“命令”(可能的构建命令)和“平台”(您应该使用相应命令的设备)。

此外,当目标平台无法在您的设备上构建时,将显示一个包含构建平台矩阵的表格,并带有一个信息性消息。

重大变化

在上述“错误处理”中,我们不得不将一些重要属性标记为必需。

以下属性现在是“必需”的(必须提供和可见)当创建它们的类的实例时:

错误修复

以下问题已成功修复:

特别感谢活跃的 Flet 社区报告了他们遇到的所有问题。我们将继续努力解决剩余的问题。

废弃

  • 所有 Page.window_*** 属性现在已废弃,已移动到 Page.window 属性,该属性的类型为 Window。 要迁移,请简单地使用 window_ 替换为 window.,如下所示:

    # 之前
    page.window_height = 200
    page.on_window_event = lambda e: print(e.type)

    # 现在
    page.window.height = 200
    page.window.on_event = lambda e: print(e.type)
  • SafeArea.minimum 已废弃,已重命名为 minimum_padding

  • MaterialState 枚举已废弃,已重命名为 ControlState

  • NavigationDestination 已废弃,已重命名为 NavigationBarDestination

此外,废弃策略已修改。在 Flet 为 pre-1.0 时,所有废弃都会在下一个 3 个版本后从 API 中删除。 所以在 v0.23.0 中(以及之前版本中)进行的上述废弃,将在 v0.26.0 中删除。

就是这样! :)

升级到 Flet 0.23.0,测试您的应用程序,并让我们知道您对新功能的看法。 如果您有任何问题,请加入 Flet Discord 服务器 或创建一个新的线程 Flet GitHub 讨论

祝您愉快地使用 Flet!

Flet 在 PyCon US 2024

· 阅读需 2 分钟
Feodor Fitsner
Flet 创始人和开发者

上周我们参加了在宾夕法尼亚州匹茨堡市举行的 PyCon US 2024 大会!

我参加过许多会议,但在 PyCon 上,我被大会的场地、组织、内容质量和友好社区深深折服 😎,...还有美味的食物 🍔!

我们遇到了很多伟大的人,特别是来自 Beeware 的好人(你好,Russell,Malcolm 和 Russell 👋)。他们在推广 Python 在移动设备上的应用和倡导在 Python 3.13 的下一个版本中添加 iOS 和 Android 平台方面做出了杰出贡献 🎉!

我们享受了精彩的演讲和激励人心的主题演讲,学习了新知识,享受了城市的美景。闪电演讲(短短 5 分钟的演讲)真是太有趣了!

我在微软展台上见到了 Guido van Rossum (Python 的创始人,如果你不知道 😅),但没有机会和他合影,因为有排队的人 😉。

作为首次参加 PyCon 的人,我们没有做演讲或展示,而是观看和学习。

我们计划明年参加演讲 🤞。

下一届 PyCon US 将在同一地点举行。我们将再次参加,希望看到更多的你们!

Flet 打包更新

· 阅读需 10 分钟
Feodor Fitsner
Flet 创始人和开发者

问题

当您将 Flet 程序打包成在移动设备(或桌面设备)上运行的 Python 程序时,生成的包(.apk、.ipa、.exe、.app)包含您的 Python 程序、Python 解释器和 Python 标准库

如果您的程序只使用 Python 标准库,那么打包过程相对简单——Flet 会将您的代码压缩并将 Flutter 应用程序与为目标平台(Android 或 iOS)编译的 Python 解释器和标准库组合在一起。

然而,当您的 Flet 程序使用第三方包时,可能会出现问题,而这些包有数千个发布在 PyPI 或 Conda 上。

第三方包有两种类型:

纯 Python 包

“纯 Python”包是仅包含 Python 代码的包,不包括用 C、C++、Rust 或其他语言编写的扩展。您只需要一个 Python 解释器和 Python 标准库即可运行纯 Python 包,而无需关心您的操作系统或平台。

此类包的示例:httpxclickrichrequests

要验证包是否纯粹,请在 PyPI 上找到该包并导航到其“下载文件”页面。如果在“已构建分发”部分下只有一个以 -py3-none-any.whl 结尾的 wheel,那么很可能它是一个纯 Python 包,可以在任何带有 Python 的设备上“按原样”运行。

我们说*“可能”*是因为该纯包可能依赖于非纯包,例如 pydantic 是一个纯包,但它需要使用 Rust 编写的 pydantic-core 非纯包才能正常工作。

非纯 Python 包

“非纯 Python”包是部分或全部用 C、C++、Rust 或其他语言编写并必须为其运行的平台编译为机器码的包。

此类包的示例:cryptographyopencv-pythonnumpymsgpack

在非纯包的“下载文件”页面上,您会发现为各种平台预构建的轮子:macOS、Windows、Linux。

当您运行 pip install <package> 时,pip 会尝试根据轮子后缀查找特定平台和 Python 版本的轮子。

这是包开发者提供的礼貌行为,为多个平台提供预编译的轮子。某些平台可能缺少轮子,或者没有轮子——只有“源分发”中的 .tar.gz 包含包源代码。

从源代码构建包很难

要安装仅具有源代码分发的包,pip 会尝试使用安装的编译器、链接器、库和 SDK 在您的机器上构建非 Python 代码。然而,这个过程可能既漫长又容易出错。编译后的代码库可能很大,并且您的机器可能缺少所需的库或工具链。

还没有适用于 iOS 和 Android 的轮子

PyPI 上还没有适用于 iOS 和 Android 的预构建轮子,并且 PyPI 的验证过程不允许包开发者上传这些轮子,因为 iOS 和 Android 都不是 Python 的正式支持平台。

有一个过程(PEP 730PEP 738)将为 Python 3.13 添加对 iOS 和 Android 的正式支持,因此,希望开发者体验将有所改善。

包依赖关系

纯 Python 包可以导入或依赖非纯包,在将您的 Flet 应用程序打包以在移动设备上运行时,您应该牢记这一点。

例如,supabase 包用于访问 Supabase API,是一个依赖于 pydantic 包的纯包,而 pydantic 包本身依赖于用 Rust 编写的 pydantic-core 非纯包。因此,要运行使用 Supabase API 的 Flet 应用程序,打包过程应该能够找到适合目标平台的预构建轮子。如果 PyPI 没有该轮子,那么要么是 Flet 开发人员在他们的服务器上构建该轮子并托管它,要么是您在自己的机器上构建该轮子。

要查看包的依赖关系图,您可以使用 pipgrip

使用 --tree 选项运行它以获得依赖关系树视图:

$ pipgrip --tree fastapi

fastapi (0.110.3)
├── pydantic!=1.8,!=1.8.1,!=2.0.0,!=2.0.1,!=2.1.0,<3.0.0,>=1.7.4 (2.7.1)
│ ├── annotated-types>=0.4.0 (0.6.0)
│ ├── pydantic-core==2.18.2 (2.18.2)
│ │ └── typing-extensions!=4.7.0,>=4.6.0 (4.11.0)
│ └── typing-extensions>=4.6.1 (4.11.0)
├── starlette<0.38.0,>=0.37.2 (0.37.2)
│ └── anyio<5,>=3.4.0 (4.3.0)
│ ├── idna>=2.8 (3.7)
│ └── sniffio>=1.1 (1.3.1)
└── typing-extensions>=4.8.0 (4.11.0)

当前方法

我们在4 个月前发布了打包的第一个版本,自那时以来,我们意识到初始方法存在多个缺陷,需要改进。

当您使用当前版本的 Flet 运行 flet build apk 时,它会下载为 Android(或如果使用 flet build ipa 运行时为 iOS)预构建的 Python 运行时和标准库。

对于非纯包,例如 numpy,Flet 要求您使用 Kivy 的“Python for Android”(p4a)工具自行构建这些包,然后提供一个路径到预构建包可以找到的“p4a”分发包。

这是问题 #1 - 您被迫与在您的机器上安装“p4a”工具并编译 Python 模块的复杂过程作斗争。

问题 #2 - 来自 p4a 的 dist 目录中的所有包将被包含在最终的应用程序包中 - 它可能包含无关的包和其他垃圾。

问题 #3 - 非纯包必须在运行 flet build 命令之前构建。您必须分析应用程序的所有依赖项,并分离出必须使用 p4a 构建的内容。

问题 #4 - p4a 的“配方”可能非常旧或缺失。您希望旧版本的包适用于您的应用程序,尝试编写“配方”并希望它能工作,或者在 Kivy 存储库中提交新配方的请求。

当您完成使用 p4a 构建非纯包时,Flet 要求您在 requirements.txt 中仅指定纯包,这在纯包直接或间接依赖于非纯包时不起作用(请参见上述示例) - 这是问题 #5。有一个最近的例子说明了这个问题:flet buildrequirements.txt 中用 flet-embed 替换 flet,但它无法知道是否有第三方包依赖于 flet,因此会安装 flet-embed 和不适用于移动设备的 flet。这不是解决方案,而是一个黑客!

打包 2.0

在 Flet 打包实现的下一次迭代中,我们将放弃 Kivy 并用 Mobile Forge 取而代之。Mobile Forge 是由 Beeware 团队基于他们在 Briefcase 和 Chaquopy 上的经验创建的。Mobile Forge 是一个用于二进制 Python 包的打包

工具的清洁实现,依赖于 crossenv

Mobile Forge 和 crossenv 的主要承诺是,大多数现有的非纯 Python 包将能够通过简单地添加一个 meta.yaml 文件的配方来为 iOS 和/或 Android 编译,而无需任何黑客或补丁。

我们将使用 Mobile Forge 为 iOS 和 Android 预构建最流行的非纯 Python 包,并在我们自己的公共存储库中托管它们。您将能够使用该工具来构建和贡献其他不在我们存储库中的包。

我们在 Flet 讨论中创建了一个新的“包”类别,您可以在其中发布、投票和讨论适用于 Flet 的非纯(本机)Python 包的请求(在发布之前请查看规则)。Flet 的目标是提供最全面的预构建 Python 包目录,并使添加新包的过程尽可能友好和透明。

新版本的 flet build 将使用自定义的虚拟 pip 索引。此索引将分析依赖项,检测非纯包,并提供 pip 移动包。对于所有其他包,它将回退到 PyPI。

希望新的打包版本将在几周内可用。在我们工作期间,我们鼓励您访问并查看您需要的包是否在那里。提交请求或为现有包投票将帮助我们优先处理包的“配方”。

谢谢!

控件和主题增强

· 阅读需 6 分钟
Henri Ndonko
Flet 贡献者和维护者

在发布 Flet 0.21.0 一个多月后,我们很高兴地宣布发布 Flet 0.22.0。

此版本带来了许多增强、错误修复和弃用功能:

增强功能

这是本次发布的主要关注点之一。我们进行了两种类型的增强:

控件增强

我们遍历了现有控件的长列表,并在可能的情况下公开了更多属性 - PR #2882。这将为您提供更多对 Flet 控件的控制,以便在您的优秀应用程序中使用。

以下是完整列表:

  • AppBar: elevation_on_scroll, exclude_header_semantics, force_material_transparency, is_secondary, shadow_color, surface_tint_color, clip_behavior, title_spacing, toolbar_opacity, title_text_style, toolbar_text_style, shape
  • AlertDialog: action_button_padding, clip_behavior, icon_padding, shadow_color, surface_tint_color
  • Banner: content_text_style, margin, elevation, divider_color, shadow_color, surface_tint_color, on_visible
  • CupertinoListTile: leading_size, leading_to_title
  • CupertinoSegmentedButton: click_color
  • CupertinoSwitch:on_label_color, off_label_color
  • CupertinoTimerPicker: item_extent
  • Chip: surface_tint_color, color, click_elevation, clip_behavior, visual_density, border_side
  • Divider: leading_indent, trailing_indent
  • ExpansionTile: dense, enable_feedback, visual_density
  • Card: clip_behavior, is_semantic_container, show_border_on_foreground, variant
  • Checkbox: border_side, semantics_label, shape, splash_radius, is_error, visual_density, mouse_cursor
  • CircleAvatar: on_image_error
  • DataTable: clip_behavior
  • DatePicker: on_entry_mode_change
  • Draggable: on_drag_complete, on_drag_start
  • DragTarget: on_move
  • Dropdown: fill_color, hint_content, icon_content, elevation, item_height, max_menu_height, icon_size, enable_feedback, padding, icon_enabled_color, icon_disabled_color, on_click
  • ElevatedButton: clip_behavior
  • FloatingActionButton: clip_behavior, enable_feedback, focus_color, foreground_color, disabled_elevation, elevation, focus_elevation, highlight_elevation, hover_elevation, mouse_cursor
  • GridView: cache_extent, clip_behavior, semantic_child_count
  • IconButton: alignment, disabled_color, focus_color, enable_feedback, hover_color, padding, splash_color, splash_radius, focus_color, mouse_cursor, visual_density
  • Image: exclude_from_semantics, filter_quality
  • ListTile: enable_feedback, horizontal_spacing, min_leading_width, min_vertical_padding, selected_color, selected_tile_color, style, title_alignment, icon_color, text_color, shape, visual_density, mouse_cursor, title_text_style, subtitle_text_style, leading_and_trailing_text_style
  • ListView: cache_extent, clip_behavior, semantic_child_count
  • NavigationBar: animation_duration, overlay_color
  • NavigationDrawerDestination: bgcolor
  • NavigationDestination: bgcolor
  • NavigationRail: selected_label_text_style, unselected_label_text_style
  • NavigationRailDestination: indicator_color, indicator_shape
  • Option: alignment, on_click
  • OutlinedButton: clip_behavior
  • Page: locale_configuration
  • PopupMenuItem: height, padding, mouse_cursor
  • PopupMenuButton: bgcolor, clip_behavior, elevation, enable_feedback, icon_color, shadow_color, surface_tint_color, icon_size, padding, splash_radius, shape, on_open, on_cancel
  • ProgressBar: border_radius, semantics_label, semantics_value
  • ProgressRing: semantics_label, semantics_value, stroke_cap, stroke_align
  • Radio: focus_color, hover_color, overlay_color, splash_radius, toggleable, visual_density, mouse_cursor
  • SearchBar: keyboard_type, view_surface_tint_color, autofocus
  • SelectionArea: on_change
  • Slider: interaction, overlay_color, mouse_cursor, secondary_track_value, secondary_active_color
  • Stack: alignment, fit
  • SnackBar: clip_behavior, shape, on_visible, action_overflow_threshold
  • Switch: hover_color, splash_radius, overlay_color, track_outline_color, mouse_cursor
  • Tabs: divider_height, enable_feedback, indicator_thickness, is_secondary, mouse_cursor, clip_behavior
  • TextField: fill_color, hover_color
  • TimePicker: orientation, on_entry_mode_change
  • Tooltip: enable_tap_to_dismiss, exclude_from_semantics
  • VerticalDivider: leading_indent, trailing_indent

如果您觉得有些功能缺失且需要添加,请随时告诉我们。

查看我写的关于 Page.locale_configuration 的文章这里

主题增强

用于应用程序主题设置的 Theme 类在浅色和深色模式下得到了进一步增强。 引入了许多新主题 - PR #2955

查看主题指南 这里

Rive 动画

Rive 是一个非常流行的实时交互设计和动画工具。 新引入的 Rive 控件允许您在应用程序中加载和可视化任何 Rive 动画。

动画的来源 (Rive.src) 可以是本地资源文件或 URL - 如常所述,这完全取决于你的需求。

父控件

根据 #952 的请求,已添加访问任何控件父级的功能:Control.parent

阅读更多内容 这里

错误修复

成功修复了以下问题:

  • #2560 - Dropdown.bgcolor 未得到视觉上的尊重
  • #2740 - CircleAvatar 无法与本地资产图像一起使用
  • #2781 - Linux 上引发了 'FletSocketServer' 错误
  • #2826 - PopupMenuItem.data 未得到尊重
  • #2839 - ExpansionTile.initially_expanded 无视觉效果
  • #2867 - PopupMenuButton 始终显示“显示菜单”工具提示
  • 在某些 Python 版本上,您可能会看到 RuntimeError('Event loop is closed'),通常在关闭应用程序窗口时显示。Python-dev 团队最近修复了这一 asyncio 相关的问题,但该修复仅存在于 2024 年发布的版本中。因此,如果您遇到此问题,请下载最新的 Python 版本之一并替换您环境中使用的版本。

特别感谢 Flet 动态社区报告他们遇到的所有问题。我们将继续努力解决剩余的问题。

弃用

如前面在有关 Flet v0.21.0 的 公告 中提到的,所有弃用将在版本 1.0 中完全从 API 中删除 - 因此您有足够的时间来更新您的应用程序。

您无需完全记住哪些内容已弃用,因为我们添加了 DeprecationWarnings,它们将直接显示在您的控制台中(不会破坏您的应用程序)。

文档

Flet 文档已重新组织,以便于导航(特别是对于初学者/新用户)。

升级到 Flet 0.22.0,测试您的应用程序,并告诉我们您对新增功能的看法。 如果您有任何问题,请加入 Flet Discord 服务器 或在 Flet GitHub 讨论 中创建一个新主题。

祝您使用 Flet 愉快!

Flet FastAPI 和异步 API 改进

· 阅读需 9 分钟

Flet 使编写动态的实时 Web 应用程序变得非常有趣!

Flet 0.21.0 进一步改进了 Web 应用程序开发体验以及在 Flet 应用中使用 asyncio API 的体验。

以下是Flet 0.21.0的新功能:

用Uvicorn的FastAPI取代内置Web服务器

从Flet诞生之初开始,用于服务Web应用的内置Web服务器是用Go编写的,名为“Fletd”。当你运行flet run --web命令时,它会在后台启动。Fletd是Flet Python轮子的一部分,增加了几兆字节的大小。此外,Python应用使用WebSockets与Fletd Web服务器通信,有时会增加明显的开销。

Flet 0.10.0中,我们添加了对FastAPI的支持,以使用AsyncIO API构建“严肃的”Web应用。

现在,在Flet 0.21.0中,内置Web服务器已被完全移除,取而代之的是FastAPI和Uvicorn。Fletd不再是Flet分发版的一部分。

使用FastAPI意味着不再有通信开销,因为Web服务器是Flet应用的一部分。此外,你不需要做任何额外的步骤即可使用FastAPI在生产环境中托管你的应用——只需使用相同的ft.app(main)命令运行你的应用。

重大变更

flet_fastapi包已被弃用,其内容已移至flet包中的flet.fastapi模块。如果你在Flet应用中使用了FastAPI,请将:

import flet_fastapi

替换为:

import flet.fastapi as flet_fastapi

使用任何 ASGI Web 服务器进行托管

你可以使用任何兼容 ASGI 的服务器托管你的 Flet Web 应用程序,如 Uvicorn(默认使用),HypercornDaphne

只需告诉 Flet 导出 ASGI 应用程序:

main.py
import flet as ft

def main(page: ft.Page):
page.add(ft.Text("Hello ASGI!"))

app = ft.app(main, export_asgi_app=True)

然后用 Hypercorn 运行:

hypercorn main:app --bind 0.0.0.0:8000

Web应用环境变量

Web 应用程序托管的每个方面都可以通过环境变量控制:

  • FLET_FORCE_WEB_SERVER - 设置为 true 强制运行应用程序作为 Web 应用程序。在无头 Linux 主机上自动设置。
  • FLET_SERVER_PORT - 运行应用程序的 TCP 端口。如果程序在 Linux 服务器上运行或设置了 FLET_FORCE_WEB_SERVER,则为 8000;否则为随机端口。
  • FLET_SERVER_IP - 监听 Web 应用程序的 IP 地址,例如 127.0.0.1。默认是 0.0.0.0 - 绑定到所有服务器 IP。
  • FLET_ASSETS_DIR - 应用程序 "assets" 目录的绝对路径。
  • FLET_UPLOAD_DIR - 应用程序 "upload" 目录的绝对路径。
  • FLET_MAX_UPLOAD_SIZE - 允许上传文件的最大大小,以字节为单位。如果未指定,则不受限制。
  • FLET_SECRET_KEY - 签署临时上传 URL 的密钥。
  • FLET_WEB_APP_PATH - 域名后的 URL 路径,用于托管 Web 应用程序,例如 /apps/myapp。默认是 / - 在根目录下托管应用程序。
  • FLET_SESSION_TIMEOUT - 会话的生命周期,以秒为单位。默认是 3600
  • FLET_OAUTH_STATE_TIMEOUT - 完成 OAuth Web 流程的最长允许时间,以秒为单位。默认是 600
  • FLET_WEB_RENDERER - Flutter 渲染模式:canvaskit(默认),htmlauto
  • FLET_WEB_USE_COLOR_EMOJI - 设置为 trueTrue1 以加载带有彩色表情符号的 Web 字体。
  • FLET_WEB_ROUTE_URL_STRATEGY - path(默认)或 hash
  • FLET_WEBSOCKET_HANDLER_ENDPOINT - WebSocket 处理程序的自定义路径。默认是 /ws
  • FLET_UPLOAD_HANDLER_ENDPOINT - 上传处理程序的自定义路径。默认是 /upload
  • FLET_OAUTH_CALLBACK_HANDLER_ENDPOINT - OAuth 处理程序的自定义路径。默认是 /oauth_callback

异步优先框架

Flet 现在是一个异步优先框架,这意味着你不必决定你的应用程序是完全同步还是异步,你可以在同一个应用程序中混合使用同步和异步方法。

例如,在 Flet 0.21.0 中,你可以这样编写一个应用程序:

import flet as ft
import time
import asyncio

def main(page: ft.Page):

def handler(e):
time.sleep(3)
page.add(ft.Text("Handler clicked"))

async def handler_async(e):
await asyncio.sleep(3)
page.add(ft.Text("Async handler clicked"))

page.add(
ft.ElevatedButton("Call handler", on_click=handler),
ft.ElevatedButton("Call async handler", on_click=handler_async)
)

ft.app(main)

在上面的示例中,点击一个按钮由“阻塞”处理程序处理,而点击第二个按钮调用异步处理程序。第一个处理程序在threading.Thread中运行,而第二个处理程序在asyncio.Task中运行。

此外,请注意在async def处理程序中不再需要使用await page.add_async(),而是可以使用常规的page.add()

API变更

大多数Page.<method>_async()Control.<method>_async()方法已被弃用,应使用其Page.<method>()Control.<method>()对应方法。

唯一的例外是返回结果的方法,例如Audio控制中的那些方法:在异步事件处理程序中仍然必须使用异步方法。

自定义控件 API 规范化

在这个 Flet 版本中,我们还重新审视了在 Python 中编写自定义控件的 API。

因此,UserControl类已被弃用。你只需继承具有适合你需求的布局的特定控件。

例如,Countdown自定义控件只是一个Text,可以如下实现:

import asyncio

import flet as ft

class Countdown(ft.Text):
def __init__(self, seconds):
super().__init__()
self.seconds = seconds

def did_mount(self):
self.running = True
self.page.run_task(self.update_timer)

def will_unmount(self):
self.running = False

async def update_timer(self):
while self.seconds and self.running:
mins, secs = divmod(self.seconds, 60)
self.value = "{:02d}:{:02d}".format(mins, secs)
self.update()
await asyncio.sleep(1)
self.seconds -= 1

def main(page: ft.Page):
page.add(Countdown(120), Countdown(60))

ft.app(main)

注意使用self.page.run_task(self.update_timer)启动新任务。 控件开发者还必须使用self.page.run_thread()方法在线程中启动新后台作业。

如果你想生成自己的任务或线程,Flet通过Page.loopPage.executor属性分别提供当前事件循环和线程执行器。

API变更

Control._before_build_command()Control.before_update()取代

Control.build()现在不应返回任何控件,而必须更新继承的控件属性,例如:

def build():
self.controls.append(ft.Text("Something"))

Control.did_mount_async()Control.will_unmount_async()已被弃用。请使用Control.did_mount()Control.will_unmount()

新的Cupertino控件

此Flet版本添加了更多Cupertino控件,使你的应用在iOS上更加出色:

  • CupertinoActivityIndicator
  • CupertinoActionSheet
  • CupertinoSlidingSegmentedButton
  • CupertinoSegmentedButton
  • CupertinoTimerPicker
  • CupertinoPicker
  • CupertinoDatePicker
  • CupertinoContextMenu

无障碍性改进

现在Flet已经完全实现了Semantics控件和新的SemanticsService控件。

应用生命周期更改事件

新增了 Page.on_app_lifecycle_state_change 事件,允许监听应用程序生命周期的变化。

例如,当应用变为活动状态(切换到前台)时,你现在可以使用最新信息更新UI。此事件适用于iOS、Android、所有桌面平台和Web!

以下是识别的应用程序生命周期转换:

  • SHOW
  • RESUME
  • HIDE
  • INACTIVE
  • PAUSE
  • DETACH
  • RESTART
备注

阅读有关每个生命周期状态的更多信息。

这是一个如何使用此事件的小示例:

import flet as ft

def main(page: ft.Page):

def app_lifecycle_change(e: ft.AppLifecycleStateChangeEvent):
if e.state == ft.AppLifecycleState.RESUME:
print("Update UI with fresh data!")

page.on_app_lifecycle_state_change = app_lifecycle_change
page.add(ft.Text("Hello World"))

ft.app(target=main)

Flet 0.21.0版本有一些重大变化。升级到它,测试你的应用,并让我们知道它的运行情况。加入Flet Discord服务器或在Flet GitHub讨论区创建一个新话题。

祝你愉快!