前言
源码来源:xilem/examples/lists.rs
适配版本:Xilem 0.4 / Masonry 0.4
一、官方完整源码
rust
// Copyright 2024 the Xilem Authors
// SPDX-License-Identifier: Apache-2.0
//! Displaying a variable length list is achieved using a [Vec] `FlexSequence`.
use winit::error::EventLoopError;
use xilem::view::{MainAxisAlignment, flex_col, prose, text_button};
use xilem::{EventLoop, WidgetView, WindowOptions, Xilem};
#[derive(Default)]
struct AppState {
count: usize,
}
fn app_logic(state: &mut AppState) -> impl WidgetView<AppState> + use<> {
// A vector (Vec) of views can be used as part of a `flex`'s children, allowing collections of dynamic length to be displayed.
let list = (0..state.count)
.map(|n| prose(format!("item #{n}")))
.collect::<Vec<_>>();
flex_col((
// Even when a `Vec` is used for the children, other widgets can be included by putting them in a
// tuple of children alongside the vector.
text_button("more", |appstate: &mut AppState| appstate.count += 1),
list,
))
// We can control alignment of the elements in the flexbox
.main_axis_alignment(MainAxisAlignment::Start) // Aligned to the left
}
fn main() -> Result<(), EventLoopError> {
let app = Xilem::new_simple(AppState::default(), app_logic, WindowOptions::new("Lists"));
app.run_in(EventLoop::with_user_event())?;
Ok(())
}
二、程序核心功能
本示例演示 动态变长列表(FlexSequence):
- 点击 more 按钮,count 计数 +1
- 根据 count 动态生成列表条目 item #0 、 item #1 ......
- 核心特性: flex_col 支持将 Vec 视图集合直接作为子元素,实现动态数量视图渲染
- 不需要循环组件、不需要宏,纯链式 Builder 写法
核心概念:FlexSequence
在 Xilem0.4 中,当把 Vec 放入 flex 的子元组,会自动识别为 FlexSequence ,用于渲染长度会变化的视图序列。
三、逐模块深度解析
1. AppState 状态结构体
rust
#[derive(Default)]
struct AppState {
count: usize,
}
- count: usize :记录列表条目总数,无符号自然数,初始默认值为0
- #derive(Default) :自动实现 Default trait,初始化时 count=0
2. 动态列表生成
rust
let list = (0..state.count)
.map(|n| prose(format!("item #{n}")))
.collect::<Vec<_>>();
- (0...state.count) :Rust 标准区间迭代器,生成 0,1,2,...,count-1
- .map(|n| prose(...)) :每一个序号生成一段文本视图 prose
- .collect::<Vec<_>>() :收集所有视图,打包成 Vec 视图数组
- prose() :Xilem 的文本组件,用于展示普通段落文字
3. flex_col 混合子元素(重点)
rust
flex_col((
text_button("more", |appstate: &mut AppState| appstate.count += 1),
list,
))
关键知识点:
flex 的子元素元组可以混合普通组件 + Vec视图数组
- 元组第一项:普通组件 text_button (固定存在的按钮)
- 元组第二项: Vec 动态视图集合(条目数量随状态改变)
Xilem 内部自动把 Vec 转为 FlexSequence,支持动态增减条目
rust
.main_axis_alignment(MainAxisAlignment::Start)
- flex_col 垂直布局,主轴为垂直方向
- MainAxisAlignment::Start :子元素靠顶部对齐
4. app_logic 与更新机制
app_logic 是视图构建函数,每次状态变更都会重新执行
- 用户点击按钮 → count +=1
- 状态更新,再次运行 app_logic
- 重新生成新的 list(条目数量+1)
- Xilem diff 新旧视图树,只增量新增对应的 item 视图
注意:
这个基础示例没有做虚拟滚动,条目极多的时候性能会下降。大量长列表需要搭配 portal(滚动容器)。
5. main 入口
rust
let app = Xilem::new_simple(AppState::default(), app_logic, WindowOptions::new("Lists"));
app.run_in(EventLoop::with_user_event())?;
- new_simple :快速创建简单应用,传入初始状态、视图逻辑、窗口配置
- 窗口标题: Lists
四、生产级拓展代码
拓展1:增加减少按钮,支持删减列表项
rust
fn app_logic(state: &mut AppState) -> impl WidgetView<AppState> + use<> {
let list = (0..state.count)
.map(|n| prose(format!("item #{n}")))
.collect::<Vec<_>>();
flex_col((
flex_row((
text_button("more", |appstate: &mut AppState| appstate.count += 1),
text_button("less", |appstate: &mut AppState| {
if appstate.count > 0 {
appstate.count -= 1;
}
}),
)),
list,
))
.main_axis_alignment(MainAxisAlignment::Start)
}
拓展2:套入 portal,实现长列表滚动
rust
fn app_logic(state: &mut AppState) -> impl WidgetView<AppState> + use<> {
let list = (0..state.count)
.map(|n| prose(format!("item #{n}")))
.collect::<Vec<_>>();
let content = flex_col((
text_button("more", |appstate: &mut AppState| appstate.count += 1),
list,
))
.main_axis_alignment(MainAxisAlignment::Start);
portal(content)
}
五、本课核心知识点总结
- Xilem 0.4 的 flex 布局支持元组内混合普通组件 + Vec动态视图序列(FlexSequence),用来实现动态列表。
- prose 是基础文本组件,用于展示段落文本。
- 状态变化会重新执行 app_logic ,重新生成 Vec 列表,框架自动 diff 视图做增量更新。
- 基础动态列表无虚拟滚动,数据量大时,需要配合 portal 滚动容器。
- flex_col 的 MainAxisAlignment::Start 代表主轴起始位置对齐,垂直列表默认置顶。
六、课后习题
练习1 填空
- Xilem0.4 中,把视图集合存入Vec放入flex子元组,会自动识别为 ________。
- prose 组件的作用是 ________。
- 本示例列表条目数量保存在状态字段 ________。
- 长列表需要滚动,要使用 ________ 组件包裹内容。
填空题参考答案
- FlexSequence
- 展示段落文本
- count
- portal
练习2 判断
- flex_col 的子元组,可以同时放置普通组件和Vec视图数组。(✅正确)
- 本示例自带虚拟滚动,支持上万条数据无性能损耗。(❌错误)
- 每次点击more按钮,状态更新后app_logic会重新执行。(✅正确)
- MainAxisAlignment::Start 在 flex_col 代表子元素靠顶部对齐。(✅正确)
练习3 简答
题目:FlexSequence 动态列表的实现原理是什么?
简答题参考答案
将迭代生成的多个视图收集为 Vec ,放入flex布局的子元素元组,Xilem自动识别为FlexSequence;状态变更时app_logic重新生成新Vec,框架对比新旧视图树,增量更新列表条目,实现动态增减列表。