跳到主要内容

导航与路由

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

Flet 0.1.42 已发布,带来了导航和路由功能!

导航和路由是单页应用程序(SPA)的一个重要功能,它允许将应用程序用户界面组织成虚拟页面(视图),并在它们之间“导航”,同时应用程序的URL反映了当前的应用状态。

对于移动应用,导航和路由还可以作为深层链接到特定的应用部分。

为了在 Flet 中添加导航和路由,我们付出了更多努力 ,因为实现是基于Navigator 2.0 Flutter API的,并需要用“页面和视图”取代 Flet 的“页面”抽象。Flutter 的新导航和路由 API 有以下显著改进:

  1. 对历史堆栈的编程控制。
  2. 一种简便的方法来拦截 AppBar 中的“后退”按钮调用。
  3. 与浏览器历史的强同步。

浏览示例源代码

页面路由

页面路由是应用程序URL中 # 符号之后的部分:

如果用户未在应用程序URL中设置默认应用程序路由,则默认为 /。所有路由都以 / 开头,例如 /store, /authors/1/books/2

可以通过读取 page.route 属性获取应用程序路由,例如:

import flet as ft

def main(page: ft.Page):
page.add(ft.Text(f"Initial route: {page.route}"))

ft.app(target=main, view=ft.AppView.WEB_BROWSER)

获取应用程序URL,打开一个新的浏览器标签页,粘贴URL,修改 # 后的部分为 /test,然后按回车。你应该会看到“Initial route: /test”。

每次URL中的路由发生变化(通过编辑URL或使用浏览器历史中的后退/前进按钮),Flet 都会调用 page.on_route_change 事件处理程序:

import flet as ft

def main(page: ft.Page):
page.add(ft.Text(f"Initial route: {page.route}"))

def route_change(route):
page.add(ft.Text(f"New route: {route}"))

page.on_route_change = route_change
page.update()

ft.app(target=main, view=ft.AppView.WEB_BROWSER)

现在尝试多次更新URL哈希,然后使用后退/前进按钮!每次路由变化时,你应该会看到页面上添加了一条新消息:

可以通过更新 page.route 属性以编程方式更改路由:

import flet as ft

def main(page: ft.Page):
page.add(ft.Text(f"Initial route: {page.route}"))

def route_change(route):
page.add(ft.Text(f"New route: {route}"))

def go_store(e):
page.route = "/store"
page.update()

page.on_route_change = route_change
page.add(ft.ElevatedButton("Go to Store", on_click=go_store))

ft.app(target=main, view=ft.AppView.WEB_BROWSER)

点击“Go to Store”按钮,你会看到应用程序URL已更改,并且在浏览器历史中添加了一个新项。你可以使用浏览器“后退”按钮导航到上一个路由。

页面视图

Flet 的 Page 现在不仅仅是一个单独的页面,而是一个包含叠加在一起的 View 的容器,像三明治一起:

视图的集合代表了导航器历史。Page具有 page.views 属性来访问视图集合。

列表中的最后一个视图是当前显示在页面上的视图。视图列表必须至少有一个元素(根视图)。

要模拟页面之间的过渡,请更改 page.route 并在 page.view 列表的末尾添加一个新 View

从集合中弹出最后一个视图并在 page.on_view_pop 事件处理程序中将路由更改为“上一个”路由以返回。

在路由变化时构建视图

为了构建可靠的导航,程序中必须有一个地方根据当前路由来构建视图列表。换句话说,导航历史堆栈(由视图列表表示)必须是路由的函数。

这个地方是 page.on_route_change 事件处理程序。

让我们将所有内容放在一起,完成一个允许在两个页面之间导航的完整示例:

import flet as ft

def main(page: ft.Page):
page.title = "Routes Example"

def route_change(route):
page.views.clear()
page.views.append(
ft.View(
"/",
[
ft.AppBar(title=ft.Text("Flet app"), bgcolor=ft.Colors.SURFACE_VARIANT),
ft.ElevatedButton("Visit Store", on_click=lambda _: page.go("/store")),
],
)
)
if page.route == "/store":
page.views.append(
ft.View(
"/store",
[
ft.AppBar(title=ft.Text("Store"), bgcolor=ft.Colors.SURFACE_VARIANT),
ft.ElevatedButton("Go Home", on_click=lambda _: page.go("/")),
],
)
)
page.update()

def view_pop(view):
page.views.pop()
top_view = page.views[-1]
page.go(top_view.route)

page.on_route_change = route_change
page.on_view_pop = view_pop
page.go(page.route)


ft.app(target=main, view=ft.AppView.WEB_BROWSER)

试试使用“Visit Store”和“Go Home”按钮在页面之间导航,使用浏览器的后退/前进按钮,手动更改URL中的路由——无论怎么做都能正常工作! :)

备注

要在页面之间“导航”,我们使用了 page.go(route) - 一个辅助方法,它更新 page.route,调用 page.on_route_change 事件处理程序来更新视图,最后调用 page.update()

注意 page.on_view_pop 事件处理程序的使用。当用户点击 AppBar 控件中的自动“后退”按钮时,它会触发。在处理程序中,我们从视图集合中删除最后一个元素,并导航到其下的视图根。

路由模板

Flet 提供 TemplateRoute——一个基于 repath 库的实用类,它允许匹配类似于 ExpressJS 的路由并解析其参数,例如 /account/:account_id/orders/:order_id

TemplateRoute 与路由更改事件非常搭配:

troute = TemplateRoute(page.route)

if troute.match("/books/:id"):
print("Book view ID:", troute.id)
elif troute.match("/account/:account_id/orders/:order_id"):
print("Account:", troute.account_id, "Order:", troute.order_id)
else:
print("Unknown route")

你可以在这里阅读更多关于 repath 库支持的模板语法。

今天就到这里!

尝试 Flet告诉我们你的想法吧!

新版本发布:拖放、绝对定位和可点击容器

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

我们刚刚发布了 Flet 0.1.41,其中包含拖放支持以及其他一些不错的功能,如堆栈中控件的绝对定位和可点击容器!

拖放

在 Flet 中实现拖放非常愉快——这要归功于 Flutter 中智能的拖放实现!您只需使用 "draggable" 控件将其拖到 "drag target" 上,当拖动项被放置时,会调用 on_accept 事件处理程序。

查看 拖放示例

探索 DraggableDragTarget 控件,它们的属性和事件。

堆栈中的绝对定位

现在所有可见控件都有 lefttoprightbottom 属性,可以让它们在 Stack 内进行绝对定位,例如:

import flet as ft

def main(page: ft.Page):

page.horizontal_alignment = ft.CrossAxisAlignment.CENTER
page.vertical_alignment = ft.MainAxisAlignment.CENTER

page.add(
ft.Container(
ft.Stack(
[
ft.Text("1", color=ft.Colors.WHITE),
ft.Text("2", color=ft.Colors.WHITE, right=0),
ft.Text("3", color=ft.Colors.WHITE, right=0, bottom=0),
ft.Text("4", color=ft.Colors.WHITE, left=0, bottom=0),
ft.Text("5", color=ft.Colors.WHITE, left=40, top=35),
]
),
border_radius=8,
padding=5,
width=100,
height=100,
bgcolor=ft.Colors.BROWN_700,
)
)

ft.app(target=main)

可点击容器

Container 控件获得了 on_click 事件,使您可以将任何控件变成按钮,并在 ink 设置为 True 时具有漂亮的材质波纹效果!

查看上述示例的 源代码

试用 Flet告诉我们 您的想法!

在 Flet 应用中使用自定义字体

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

现在,您可以在 Flet 应用中使用自己的字体了!

支持以下字体格式:

  • .ttc
  • .ttf
  • .otf

使用 page.fonts 属性导入字体。

page.fonts 属性设置为一个字典,其中键是字体系列名称,用于引用该字体,值是要导入的字体文件的 URL:

def main(page: ft.Page):
page.fonts = {
"Kanit": "https://raw.githubusercontent.com/google/fonts/master/ofl/kanit/Kanit-Bold.ttf",
"Aleo Bold Italic": "https://raw.githubusercontent.com/google/fonts/master/ofl/aleo/Aleo-BoldItalic.ttf"
}
page.update()

# ...

字体可以通过提供绝对 URL 从外部资源导入,或者通过提供相对 URL 和 assets_dir 从应用程序资源中导入。

flet.app() 调用中指定 assets_dir,以设置应该提供给应用程序的资产位置。assets_dir 可以是相对于您的 main.py 目录的路径,也可以是绝对路径。例如,考虑以下程序结构:

/assets
/fonts
/OpenSans-Regular.ttf
main.py

代码示例

以下程序从 GitHub 加载 "Kanit" 字体,并从资源中加载 "Open Sans"字体。 "Kanit" 被设置为默认应用字体,而 "Open Sans" 用于特定的文本控件:

import flet as ft

def main(page: ft.Page):
page.title = "Custom fonts"

page.fonts = {
"Kanit": "https://raw.githubusercontent.com/google/fonts/master/ofl/kanit/Kanit-Bold.ttf",
"Open Sans": "fonts/OpenSans-Regular.ttf",
}

page.theme = ft.Theme(font_family="Kanit")

page.add(
ft.Text("This is rendered with Kanit font"),
ft.Text("This is Open Sans font example", font_family="Open Sans"),
)

ft.app(target=main, assets_dir="assets")

静态字体与可变字体

目前仅支持静态字体,即仅包含一种特定宽度/粗细/样式组合的字体,例如 "Open Sans Regular" 或 "Roboto Bold Italic"。

可变字体支持仍在开发中

但是,如果您需要在应用中使用可变字体,可以使用 fonttools 创建特定权重的静态“实例化”,然后使用这些实例:

fonttools varLib.mutator ./YourVariableFont-VF.ttf wght=140 wdth=85

要探索可用的字体特性(例如 wght 的可能选项),可以使用 Wakamai Fondue 在线工具。

试试 Flet告诉我们您的想法!

介绍 Flet

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

今天我们宣布 Flet 的第一个版本发布了!

Flet 是一个用于使用 Python 构建实时网络、桌面和移动应用的框架。

无需使用复杂的 JavaScript 前端、REST API 后端、数据库、缓存等架构。使用 Flet,你只需编写一个 Python 状态单体应用程序,即可获得多用户、实时单页应用程序 (SPA) 或移动应用程序。

要开始使用 Flet 开发,你只需要你喜欢的 IDE 或文本编辑器。无需 SDK,无需数千个依赖项,无需复杂的工具链——Flet 内置了带有资产托管的 Web 服务器和桌面客户端。

Flet UI 使用 Flutter 构建,因此你的应用程序看起来很专业,并且可以交付到任何平台。Flet 通过将较小的“widgets”组合成可立即使用的“controls”并采用命令式编程模型来简化 Flutter 模型。 你可以获得 Flutter 的所有强大功能,而无需学习 Dart!

Flet 应用程序作为常规 Web 应用程序部署,可以立即通过浏览器访问或安装为移动设备上的 PWA。Web 应用程序还公开了一个 API,可以被运行在 iOS 和 Android 上的 Flet 客户端(计划在未来版本中推出)使用,提供原生移动体验。

以下是一些示例:

试试 Flet告诉我们你的想法!