跳到主要内容

大型列表 Large lists

在大多数情况下,您可以使用ColumnRow控件来显示列表,但如果列表包含数百或数千个项目,则ColumnRow将无效,因为它们一次渲染所有项目,即使它们在当前滚动位置上不可见,也会导致界面卡顿。

在下面的示例中,我们向页面添加了5,000个文本控件。页面使用Column作为默认的布局容器:

import flet as ft

def main(page: ft.Page):
for i in range(5000):
page.controls.append(ft.Text(f"Line {i}"))
page.scroll = "always"
page.update()

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

运行程序并注意,它不仅需要几秒钟的时间来初始化加载和渲染页面上的所有文本行,而且滚动也很慢和卡顿:

为了显示具有大量项目的列表,请使用ListViewGridView控件,它们仅在当前滚动位置可见时才渲染项目。

ListView

ListView可以是垂直的(默认)或水平的。ListView项目在滚动方向上依次显示。

ListView已经实现了对其子项的有效按需渲染,但如果您可以为所有项设置相同的固定高度或宽度(对于horizontal ListView),则滚动性能可以进一步提高。可以通过设置item_extent属性来设置绝对范围,或者通过将所有子项的范围设置为第一个子项的范围来将所有子项的范围设置为相同的范围,方法是将first_item_prototype设置为True

让我们使用ListView控件输出一个包含5,000个项目的列表:

import flet as ft

def main(page: ft.Page):
lv = ft.ListView(expand=True, spacing=10)
for i in range(5000):
lv.controls.append(ft.Text(f"Line {i}"))
page.add(lv)

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

现在,滚动是平滑且足够快,可以跟随鼠标移动:

备注

我们在ListView构造函数中使用了expand=True。为了正常工作,ListView必须指定高度(或宽度,如果是horizontal)。您可以设置绝对大小,例如ListView(height=300, spacing=10),但在上面的示例中,我们使ListView占用页面上的所有可用空间,即扩展。了解更多关于Control.expand属性的信息。

GridView

GridView允许将控件排列成可滚动的网格。

您可以使用ft.Column(wrap=True)ft.Row(wrap=True)创建一个“网格”,例如:

import os
import flet as ft

os.environ["FLET_WS_MAX_MESSAGE_SIZE"] = "8000000"

def main(page: ft.Page):
r = ft.Row(wrap=True, scroll="always", expand=True)
page.add(r)

for i in range(5000):
r.controls.append(
ft.Container(
ft.Text(f"Item {i}"),
width=100,
height=100,
alignment=ft.alignment.center,
bgcolor=ft.colors.AMBER_100,
border=ft.border.all(1, ft.colors.AMBER_400),
border_radius=ft.border_radius.all(5),
)
)
page.update()

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

尝试滚动和调整浏览器窗口大小-一切都可以工作,但非常卡顿。

备注

在程序开始时,我们设置了FLET_WS_MAX_MESSAGE_SIZE环境变量的值为8000000-这是Flet服务器可以接收的WebSocket消息的最大字节大小。默认大小为1 MB,但描述5,000个容器控件的JSON消息的大小将超过1 MB,因此我们将允许的大小增加到8 MB。

通常,通过WebSocket通道传输大型消息并不是一个好主意,因此使用批量更新方法来控制通道负载。

GridView与ListView类似,非常有效地渲染大量子项。让我们使用GridView来实现上面的示例:

import os
import flet as ft

os.environ["FLET_WS_MAX_MESSAGE_SIZE"] = "8000000"

def main(page: ft.Page):
gv = ft.GridView(expand=True, max_extent=150, child_aspect_ratio=1)
page.add(gv)

for i in range(5000):
gv.controls.append(
ft.Container(
ft.Text(f"Item {i}"),
alignment=ft.alignment.center,
bgcolor=ft.colors.AMBER_100,
border=ft.border.all(1, ft.colors.AMBER_400),
border_radius=ft.border_radius.all(5),
)
)
page.update()

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

使用GridView进行滚动和窗口调整大小时,界面是平滑且响应迅速的!

您可以使用runs_count属性指定固定行数或列数(runs),或者使用max_extent属性指定“tile”的最大大小,以便自动变化运行的数量。在我们的示例中,我们将最大tile大小设置为150像素,并将其形状设置为“正方形”,使用child_aspect_ratio=1。尝试将其更改为0.52

批量更新

当调用page.update()时,将通过WebSockets向Flet服务器发送一条消息,该消息包含自上次page.update()以来的页面更新。发送包含数千个添加的控件的大型消息可能会导致用户等待几秒钟,直到消息完全接收并渲染控件。

为了增加程序的可用性并尽快向用户呈现结果,您可以将页面更新分批发送。例如,以下程序将5,100个子控件分批添加到ListView中,每批添加500个项目:

import flet as ft

def main(page: ft.Page):

# 首先将ListView添加到页面中
lv = ft.ListView(expand=1, spacing=10, item_extent=50)
page.add(lv)

for i in range(5100):
lv.controls.append(ft.Text(f"Line {i}"))
# 将页面发送给页面
if i % 500 == 0:
page.update()
# 发送剩余的页面
page.update()

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