Flexbox 布局
单个矩形无趣——UI 的核心是多个元素的排列方式。Bevy 的默认布局算法是 Flexbox(和 CSS 的 Flexbox 同源),由 Node 的 flex_direction 字句控制主轴方向。
行布局
把 flex_direction 设为 FlexDirection::Row,子节点就从左到右排列:
use bevy::prelude::*;
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_systems(Startup, setup)
.run();
}
fn setup(mut commands: Commands) {
commands.spawn(Camera2d);
commands
.spawn((
Node {
width: Val::Percent(100.0),
height: Val::Percent(100.0),
flex_direction: FlexDirection::Row,
align_items: AlignItems::Center,
column_gap: Val::Px(12.0),
padding: UiRect::all(Val::Px(20.0)),
..default()
},
BackgroundColor(Color::srgb(0.1, 0.1, 0.1)),
))
.with_children(|parent| {
parent.spawn((
Node {
width: Val::Px(80.0),
height: Val::Px(80.0),
..default()
},
BackgroundColor(Color::srgb(0.9, 0.2, 0.2)),
));
parent.spawn((
Node {
width: Val::Px(80.0),
height: Val::Px(80.0),
..default()
},
BackgroundColor(Color::srgb(0.2, 0.9, 0.2)),
));
parent.spawn((
Node {
width: Val::Px(80.0),
height: Val::Px(80.0),
..default()
},
BackgroundColor(Color::srgb(0.2, 0.2, 0.9)),
));
});
}Listing 28-2:FlexDirection::Row——三个色块水平排列(examples/listing-28-02.rs)
这段代码用 with_children 闭包在父节点下添加三个子节点。column_gap: Val::Px(12.0) 在子节点之间插入 12 像素的间距,align_items: AlignItems::Center 让子节点在交叉轴(垂直方向)居中。
列布局
把 flex_direction 改为 FlexDirection::Column,子节点就从上到下排列:
use bevy::prelude::*;
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_systems(Startup, setup)
.run();
}
fn setup(mut commands: Commands) {
commands.spawn(Camera2d);
commands
.spawn((
Node {
width: Val::Percent(100.0),
height: Val::Percent(100.0),
flex_direction: FlexDirection::Column,
justify_content: JustifyContent::Center,
align_items: AlignItems::Center,
row_gap: Val::Px(10.0),
..default()
},
BackgroundColor(Color::srgb(0.1, 0.1, 0.1)),
))
.with_children(|parent| {
parent.spawn((
Node {
width: Val::Px(200.0),
height: Val::Px(50.0),
..default()
},
BackgroundColor(Color::srgb(0.9, 0.3, 0.3)),
));
parent.spawn((
Node {
width: Val::Px(200.0),
height: Val::Px(50.0),
..default()
},
BackgroundColor(Color::srgb(0.3, 0.9, 0.3)),
));
parent.spawn((
Node {
width: Val::Px(200.0),
height: Val::Px(50.0),
..default()
},
BackgroundColor(Color::srgb(0.3, 0.3, 0.9)),
));
});
}Listing 28-3:FlexDirection::Column——三个色块垂直居中(examples/listing-28-03.rs)
justify_content: JustifyContent::Center 控制主轴(现在是垂直方向)的对齐——子节点被挤到正中间。row_gap 在列布局中控制行间距。
JustifyContent:主轴上的分布
justify_content 决定子节点在主轴上如何分布。常用值:
| 值 | 效果 |
|---|---|
FlexStart | 从主轴起点开始排列(默认) |
FlexEnd | 从主轴终点开始排列 |
Center | 居中 |
SpaceBetween | 首尾贴边,中间均匀分 |
SpaceEvenly | 所有间距相等(包括首尾) |
SpaceAround | 每个子节点两侧等距(首尾间距是中间的一半) |
AlignItems:交叉轴上的对齐
align_items 控制子节点在交叉轴(与主轴垂直的方向)上的对齐方式:
| 值 | 效果 |
|---|---|
FlexStart | 贴交叉轴起点 |
FlexEnd | 贴交叉轴终点 |
Center | 居中 |
Stretch | 拉伸填满(默认) |
Baseline | 按文字基线对齐 |
组合 justify_content 和 align_items 就能表达绝大多数一维布局需求:
use bevy::prelude::*;
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_systems(Startup, setup)
.run();
}
fn setup(mut commands: Commands) {
commands.spawn(Camera2d);
commands
.spawn(Node {
width: Val::Percent(100.0),
height: Val::Percent(100.0),
flex_direction: FlexDirection::Column,
row_gap: Val::Px(16.0),
padding: UiRect::all(Val::Px(24.0)),
..default()
})
.with_children(|parent| {
spawn_row(parent, JustifyContent::FlexStart);
spawn_row(parent, JustifyContent::Center);
spawn_row(parent, JustifyContent::FlexEnd);
spawn_row(parent, JustifyContent::SpaceBetween);
spawn_row(parent, JustifyContent::SpaceEvenly);
});
}
fn spawn_row(parent: &mut ChildSpawnerCommands, justify: JustifyContent) {
parent
.spawn((
Node {
width: Val::Percent(100.0),
height: Val::Px(100.0),
flex_direction: FlexDirection::Row,
justify_content: justify,
align_items: AlignItems::Center,
padding: UiRect::all(Val::Px(8.0)),
column_gap: Val::Px(8.0),
..default()
},
BackgroundColor(Color::srgb(0.2, 0.2, 0.2)),
))
.with_children(|parent| {
spawn_box(parent, Color::srgb(0.9, 0.3, 0.3));
spawn_box(parent, Color::srgb(0.3, 0.9, 0.3));
spawn_box(parent, Color::srgb(0.3, 0.3, 0.9));
});
}
fn spawn_box(parent: &mut ChildSpawnerCommands, color: Color) {
parent.spawn((
Node {
width: Val::Px(50.0),
height: Val::Px(50.0),
..default()
},
BackgroundColor(color),
));
}Listing 28-4:JustifyContent 的五种取值对比(examples/listing-28-04.rs)
子节点的 flex_grow
flex_grow(默认 0)控制子节点是否"吃掉"剩余空间。设为 1 就意味着"在所有 flex_grow 为 1 的兄弟之间按比例分配剩余空间"。这在"侧边栏固定宽度、主内容区填满"的布局中极为常用——Listing 28-5 会演示。
Reverse:反向排列
FlexDirection::RowReverse 和 FlexDirection::ColumnReverse 让子节点从终点向起点排列。用途不多,但在某些 RTL(从右到左)布局或动画中偶尔需要。
小结:flex_direction 决定主轴方向,justify_content 控制主轴分布,align_items 控制交叉轴对齐,flex_grow 让子节点分配剩余空间。这四个字段覆盖了一维布局的绝大多数场景。