VirtualList
VirtualList 是一个面向大规模数据集的高性能列表组件。它只渲染当前可见区域的项目,因此非常适合长列表、动态高度内容以及类似表格的复杂布局。
与普通均匀列表不同,VirtualList 支持每一项拥有不同尺寸。
#导入
use gpui_kit::component::{
v_virtual_list, h_virtual_list, VirtualListScrollHandle,
scroll::{Scrollbar, ScrollbarState, ScrollbarAxis},
};
use std::rc::Rc;
use gpui_kit::{px, size, ScrollStrategy, Size, Pixels};
#用法
#基础纵向列表
pub struct ListViewExample {
items: Vec<String>,
item_sizes: Rc<Vec<Size<Pixels>>>,
scroll_handle: VirtualListScrollHandle,
}
v_virtual_list(
cx.entity().clone(),
"my-list",
self.item_sizes.clone(),
|view, visible_range, _, cx| {
visible_range
.map(|ix| {
div()
.h(px(30.))
.w_full()
.bg(cx.theme().secondary)
.child(format!("Item {}", ix))
})
.collect()
},
)
.track_scroll(&self.scroll_handle)
#横向列表
h_virtual_list(
cx.entity().clone(),
"horizontal-list",
item_sizes.clone(),
|view, visible_range, _, cx| {
visible_range
.map(|ix| {
div()
.w(px(120.))
.h_full()
.bg(cx.theme().accent)
.child(format!("Card {}", ix))
})
.collect()
},
)
#可变尺寸项
let item_sizes = Rc::new(
(0..1000)
.map(|i| {
let height = if i % 5 == 0 {
px(60.)
} else if i % 3 == 0 {
px(45.)
} else {
px(30.)
};
size(px(300.), height)
})
.collect::<Vec<_>>()
);
#滚动控制
#基础滚动
pub struct ScrollableList {
scroll_handle: VirtualListScrollHandle,
scroll_state: ScrollbarState,
}
#编程式滚动
impl ScrollableList {
fn scroll_to_item(&self, index: usize) {
self.scroll_handle.scroll_to_item(index, ScrollStrategy::Top);
}
fn center_item(&self, index: usize) {
self.scroll_handle.scroll_to_item(index, ScrollStrategy::Center);
}
fn scroll_to_bottom(&self) {
self.scroll_handle.scroll_to_bottom();
}
}
#双轴滚动
Scrollbar::both(&scroll_state, &scroll_handle)
.axis(ScrollbarAxis::Both)
#性能说明
VirtualList 的核心优势在于:
- 只渲染可见范围内的项
- 滚动时复用已渲染元素
- 数据量很大时内存占用仍然稳定
因此只要列表项超过几十个,尤其是达到上百上千个时,就值得优先考虑 VirtualList。
#示例
#文件浏览器
pub struct FileExplorer {
files: Vec<FileEntry>,
item_sizes: Rc<Vec<Size<Pixels>>>,
scroll_handle: VirtualListScrollHandle,
selected_index: Option<usize>,
}
#聊天窗口
pub struct ChatWindow {
messages: Vec<ChatMessage>,
scroll_handle: VirtualListScrollHandle,
auto_scroll: bool,
}
#固定表头的数据网格
pub struct DataGrid {
headers: Vec<String>,
data: Vec<Vec<String>>,
column_widths: Vec<Pixels>,
scroll_handle: VirtualListScrollHandle,
}
#最佳实践
- 尽量预先计算 item 尺寸
- 渲染函数里避免重计算
- 列表项数量超过 50 时优先考虑 VirtualList
- 将项状态与渲染逻辑拆开管理
- 测试不同数据量和滚动位置下的表现