Latest commit 4407cdb
UI 的各种功能。
use bevy::input::mouse::{MouseScrollUnit, MouseWheel}; use bevy::prelude::*; use bevy::winit::WinitSettings; fn main() { let mut app = App::new(); app.add_plugins(DefaultPlugins); // 优化:仅在有用户输入时运行这个 app,可以减轻 CPU/GPU 负担 app.insert_resource(WinitSettings::desktop_app()); app.add_startup_system(初始设置); app.add_system(鼠标滚动); app.run(); } fn 初始设置(mut commands: Commands, asset_server: Res<AssetServer>) { // 摄像机 commands.spawn(Camera2dBundle::default()); // 根节点 commands .spawn(NodeBundle { style: Style { size: Size::new(Val::Percent(100.0), Val::Percent(100.0)), justify_content: JustifyContent::SpaceBetween, ..default() }, ..default() }) .with_children(|child_builder| { // 左垂直填充(边框) child_builder .spawn(NodeBundle { style: Style { size: Size::new(Val::Px(200.0), Val::Percent(100.0)), ..default() }, background_color: Color::rgb(0.65, 0.65, 0.65).into(), ..default() }) .with_children(|child_builder| { // 左垂直填充(内容) child_builder .spawn(NodeBundle { style: Style { size: Size::new(Val::Percent(100.0), Val::Percent(100.0)), ..default() }, background_color: Color::rgb(0.15, 0.15, 0.15).into(), ..default() }) .with_children(|child_builder| { // 文本 child_builder.spawn( TextBundle::from_section( "文本示例", TextStyle { font: asset_server.load("fonts/LXGWWenKai.ttf"), font_size: 30.0, color: Color::WHITE, }, ) .with_style(Style { margin: UiRect::all(Val::Px(5.0)), ..default() }), ); }); }); // 右垂直填充 child_builder .spawn(NodeBundle { style: Style { flex_direction: FlexDirection::Column, justify_content: JustifyContent::Center, size: Size::new(Val::Px(200.0), Val::Percent(100.0)), ..default() }, background_color: Color::rgb(0.15, 0.15, 0.15).into(), ..default() }) .with_children(|child_builder| { // 标题 child_builder.spawn( TextBundle::from_section( "滚动列表", TextStyle { font: asset_server.load("fonts/LXGWWenKai.ttf"), font_size: 25.0, color: Color::WHITE, }, ) .with_style(Style { size: Size::new(Val::Undefined, Val::Px(25.0)), margin: UiRect { left: Val::Auto, right: Val::Auto, ..default() }, ..default() }), ); // 带有隐藏溢出的列表 child_builder .spawn(NodeBundle { style: Style { flex_direction: FlexDirection::Column, align_self: AlignSelf::Center, size: Size::new(Val::Percent(100.0), Val::Percent(50.0)), overflow: Overflow::Hidden, ..default() }, background_color: Color::rgb(0.10, 0.10, 0.10).into(), ..default() }) .with_children(|child_builder| { // 正在移动面板 child_builder .spawn(( NodeBundle { style: Style { flex_direction: FlexDirection::ColumnReverse, flex_grow: 1.0, max_size: Size::UNDEFINED, ..default() }, ..default() }, ScrollingList::default(), )) .with_children(|child_builder| { // 项目列表 for i in 0..30 { child_builder.spawn( TextBundle::from_section( format!("项目 {}", i), TextStyle { font: asset_server.load("fonts/LXGWWenKai.ttf"), font_size: 20.0, color: Color::WHITE, }, ) .with_style(Style { flex_shrink: 0.0, size: Size::new(Val::Undefined, Val::Px(20.0)), margin: UiRect { left: Val::Auto, right: Val::Auto, ..default() }, ..default() }), ); } }); }); }); // 绝对定位 child_builder .spawn(NodeBundle { style: Style { size: Size::new(Val::Px(200.0), Val::Px(200.0)), position_type: PositionType::Absolute, position: UiRect { left: Val::Px(210.0), bottom: Val::Px(10.0), ..default() }, border: UiRect::all(Val::Px(20.0)), ..default() }, background_color: Color::rgb(0.4, 0.4, 1.0).into(), ..default() }) .with_children(|child_builder| { child_builder.spawn(NodeBundle { style: Style { size: Size::new(Val::Percent(100.0), Val::Percent(100.0)), ..default() }, background_color: Color::rgb(0.8, 0.8, 1.0).into(), ..default() }); }); // 渲染顺序测试:前面最白,后面最红,(弹性中心) child_builder .spawn(NodeBundle { style: Style { size: Size::new(Val::Percent(100.0), Val::Percent(100.0)), position_type: PositionType::Absolute, align_items: AlignItems::Center, justify_content: JustifyContent::Center, ..default() }, ..default() }) .with_children(|child_builder| { child_builder .spawn(NodeBundle { style: Style { size: Size::new(Val::Px(100.0), Val::Px(100.0)), ..default() }, background_color: Color::rgb(1.0, 0.0, 0.0).into(), ..default() }) .with_children(|child_builder| { child_builder.spawn(NodeBundle { style: Style { size: Size::new(Val::Px(100.0), Val::Px(100.0)), position_type: PositionType::Absolute, position: UiRect { left: Val::Px(20.0), bottom: Val::Px(20.0), ..default() }, ..default() }, background_color: Color::rgb(1.0, 0.3, 0.3).into(), ..default() }); child_builder.spawn(NodeBundle { style: Style { size: Size::new(Val::Px(100.0), Val::Px(100.0)), position_type: PositionType::Absolute, position: UiRect { left: Val::Px(40.0), bottom: Val::Px(40.0), ..default() }, ..default() }, background_color: Color::rgb(1.0, 0.5, 0.5).into(), ..default() }); child_builder.spawn(NodeBundle { style: Style { size: Size::new(Val::Px(100.0), Val::Px(100.0)), position_type: PositionType::Absolute, position: UiRect { left: Val::Px(60.0), bottom: Val::Px(60.0), ..Default::default() }, ..Default::default() }, background_color: Color::rgb(1.0, 0.7, 0.7).into(), ..default() }); // alpha 测试 child_builder.spawn(NodeBundle { style: Style { size: Size::new(Val::Px(100.0), Val::Px(100.0)), position_type: PositionType::Absolute, position: UiRect { left: Val::Px(80.0), bottom: Val::Px(80.0), ..default() }, ..default() }, background_color: Color::rgb(1.0, 0.9, 0.4).into(), ..default() }); }); }); // bevy logo(弹性中心) child_builder .spawn(NodeBundle { style: Style { size: Size::new(Val::Percent(100.0), Val::Percent(100.0)), position_type: PositionType::Absolute, justify_content: JustifyContent::Center, align_items: AlignItems::FlexStart, ..default() }, ..default() }) .with_children(|child_builder| { // bevy logo(图像) child_builder.spawn(ImageBundle { style: Style { size: Size::new(Val::Px(500.0), Val::Auto), ..default() }, image: asset_server.load("bevy_logo_dark_big.png").into(), ..default() }); }); }); } #[derive(Component, Default)] struct ScrollingList { position: f32, } fn 鼠标滚动( mut event_reader: EventReader<MouseWheel>, mut query_list: Query<(&mut ScrollingList, &mut Style, &Children, &Node)>, query_item: Query<&Node>, ) { for event in event_reader.iter() { for (mut scrolling_list, mut style, children, ui_code) in &mut query_list { let items_height: f32 = children .iter() .map(|entity| query_item.get(*entity).unwrap().size().y) .sum(); let panel_height = ui_code.size().y; let max_scroll = (items_height - panel_height).max(0.0); let dy = match event.unit { MouseScrollUnit::Line => event.y * 20.0, MouseScrollUnit::Pixel => event.y, }; scrolling_list.position += dy; scrolling_list.position = scrolling_list.position.clamp(-max_scroll, 0.0); style.position.top = Val::Px(scrolling_list.position); } } }