跳到主要内容

导航与路由

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

Flet 0.1.42已发布,其中包含导航和路由功能!

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

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

为了将导航和路由添加到Flet中,我们花费了比预期更多的努力。这个实现是基于Flutter的Navigator 2.0 API,并需要用“Page和Views”替换Flet的“Page”抽象。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"用于特定的Text控件:

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 = 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

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

试用一下Flet,并告诉我们您的想法

Flet介绍

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

今天我们宣布 Flet 的首次发布!

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

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

要开始使用 Flet 进行开发,你只需要你最喜欢的 IDE 或文本编辑器。没有 SDK,没有大量依赖,没有复杂的工具链 - Flet 内置了带有资源托管和桌面客户端的 Web 服务器。

Flet 的 UI 使用 Flutter 构建,因此你的应用程序看起来很专业,并且可以交付到任何平台上。Flet 通过将较小的 "widget" 结合为可直接使用的 "control",采用了命令式编程模型来简化 Flutter 开发。你可以在不学习 Dart 的情况下获得 Flutter 的所有功能!

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

以下是一些示例:

试用一下 Flet,并告诉我们你的想法 传送门