
Bevy FeathersSelect 下拉选择控件BSN 场景、ValueChange 事件与 SetSelected 编程式选中文档【免费下载链接】bevyA refreshingly simple>项目地址: https://gitcode.com/GitHub_Trending/be/bevy本文讲解 Bevybevy_feathers模块新引入的FeathersSelect下拉选择控件如何在bsn!场景中声明选项、配置max_visible滚动行为、通过ValueChange事件读取选中值、用新增的SetSelected事件以编程方式切换选中项以及caption()场景辅助函数的作用。读完后可直接在 Feathers 风格 UI 中构建可复选、可滚动、支持键盘焦点管理的下拉菜单。1. 控件定位基于 FeathersListView 与 FeathersMenuPopup 的下拉选择FeathersSelect是bevy_feathers中的下拉选择控件dropdown select control用于在多个选项中选择一个。它有两个设计基础复用现有列表控件选择面板内部就是FeathersListView因此天然继承列表的行样式、选中高亮与键盘导航弹出式显示打开时通过FeathersMenuPopup展示选项与FeathersMenu家族的弹出行为一致。从源码结构看控件本体是一个标记组件真正的实体树由场景生成逻辑构建见 select.rs/// Select control which spawns a menu popup with a list of string options /// # Emitted events /// * ValueChangeEntity when the selected option is changed. #[derive(SceneComponent, Default, Clone)] #[scene(FeathersSelectProps)] pub struct FeathersSelect;生成的实体层级为FeathersMenu根携带FeathersSelect→FeathersMenuButton显示当前选中项的按钮FeathersMenuPopup弹出层→FeathersListView选项列表行由传入的options决定。2. 在 BSN 场景中声明 FeathersSelect在bsn!宏内使用FeathersSelect场景实体并通过FeathersSelectProps传入属性。核心属性有属性类型默认值说明optionsBoxdyn SceneList空列表选项行集合每行通常是带FeathersListRow组件的实体max_visibleusize8滚动前最多可见的行数小于 1 时按 1 处理cornersRoundedCorners默认圆角下拉按钮的圆角样式属性定义与默认值见 FeathersSelectProps。最简用法bsn! { ( FeathersSelect { options: { list_rows_from_strings([One, Two, Three], Some(0)) }, } Node { flex_grow: 1.0, } ) }仓库示例 feathers_gallery.rs 中还有带max_visible: 6的写法——当选项行数超过max_visible时下拉面板内部会出现滚动条。滚动高度的来源是场景生成时的计算见 select.rs 与 select.rs每行固定高度SELECT_ROW_PX 28.0像素FeathersListView被加上max_height max_visible × 28px的Node约束超出部分即可滚动。3. 生成选项行list_rows_from_strings 与 OptionIndex如果选项就是一组字符串推荐用辅助函数 list_rows_from_stringspub fn list_rows_from_strings( options: impl IntoIteratorItem: AsRefstr, selected: Optionusize, ) - Boxdyn SceneList它把每个字符串转换成一行FeathersListRow场景并在每行上挂OptionIndex(usize)组件值就是该字符串在迭代器中的下标——后续收到变更事件时可以反查“选中的是第几个字符串”对selected参数指定的下标行额外挂Selected组件作为初始选中项。OptionIndex本身是一个完全可选的组件见 select.rs仅在基于字符串的选择场景中用于定位。如果选项携带更丰富的数据例如月份枚举可以像 feathers_gallery.rs 那样手工构造Boxdyn SceneListFeathersSelect { options: { Box::new( Months::ALL .into_iter() .map(|m| - Boxdyn SceneList { let label m.to_str(); if m Months::default() { bsn! { FeathersListRow Selected m Children [ caption(label) ] }.into() } else { bsn! { FeathersListRow m Children [ caption(label) ] }.into() } }) .collect::Vec_(), ) as Boxdyn SceneList }, max_visible: 6, }这里的技巧是把Months枚举组件直接挂到行实体上这样选中变更事件的value行Entity就能被组件查询解析回具体枚举值而不是依赖下标。4. 读取选中变更ValueChange 事件在控件上的重发FeathersSelect对外只承诺一个事件选中项改变时在FeathersSelect实体上发出ValueChangeEntityvalue为选中的行实体。这由内部 observer re_emit_listbox_value 完成FeathersListView内部每次行选中变化都会在其自身实体上触发ValueChangeEntityobserver 沿ChildOf向上查找事件目标找到祖先中的FeathersSelect实体后把同一个value以is_final: true重发到 select 实体上同时给祖先中的FeathersMenuPopup加上Visibility::Hidden即“选中即收起下拉面板”。因此业务代码只需在 select 实体上挂on(...)。feathers_gallery.rs 的字符串版本示例on(|change: OnValueChangeEntity, q_options: QueryOptionIndex| { let Ok(option) q_options.get(change.value) else { info!(Select changed, not sure); return; }; info!(Select changed to index {}, option.0); })而 display_and_visibility.rs 展示了用选中行的数据组件NodeDisplaySetting/NodeVisibilitySetting更新目标实体的更完整模式查询行实体上的设置组件、更新目标实体、并同步各行的Selected组件状态。5. 编程式选中SetSelected 事件本版本同时给底层bevy_ui_widgets的ListBox控件新增了SetSelected实体事件用于程序化地设置选中值与SetChecked、SetSliderValue的定位一致。事件定义见 list.rs/// Programmatically set which entity is selected (a single row of the list) /// Wraps a call to send ValueChange. No-op if already selected or disabled #[derive(EntityEvent, Reflect)] pub struct SetSelected { /// The list entity pub entity: Entity, /// The child to set value to pub row: Entity, }其处理逻辑listbox_on_set_selected目标是ListBox且行未被InteractionDisabled时若行尚未选中则触发ValueChangeEntity走正常选中流程若行已选中则触发ReselectListRow“重选”事件用于触发“再次点击已选项”的回调。FeathersSelect侧则由 observer select_on_set_selected 做转发当SetSelected触发在带FeathersSelect的实体上时向下遍历后代找到内部ListBox实体把同一行号重新以SetSelected触发到该ListBox上。这样使用者只需面向FeathersSelect实体编程无需关心内部列表实体。6. caption() 场景辅助函数本次变更还新增了一个与label()类似的 BSN 场景函数 caption/// A caption within, say, a button. pub fn caption(text: impl IntoString) - impl Scene { bsn! { Text(text) ThemedText } }与label()自带正文字号、权重和主题文本色的独立标签不同caption()只发出(Text(...) ThemedText)两个组件字体继承自父控件的样式上下文——这正是按钮、菜单项、列表行等“控件内文字”需要的行为。FeathersSelect的选项行正是用它渲染标签见 list_rows_from_strings 中的caption(label)feathers_gallery.rs 的菜单项caption: bsn! { caption(MenuItem 3) }也是同一用法。7. 内部机制速览SelectPlugin 的四个系统/观察者FeathersSelect的持续行为由 SelectPlugin 注册全部在Update调度中运行sync_caption查询“新增了Selected的FeathersListRow”取该行第一个Text子代文本写入 select 后代中带SelectCaption标记的按钮文字——即按钮上显示的当前选项标签随选中项自动更新focus_select_popup当 select 内的弹出层从可见变为隐藏、且焦点仍位于 select 内部时把InputFocus交还给FeathersMenuButton保证键盘/手柄导航的焦点不悬空sync_select_width按 select 根节点的实际计算宽度含缩放因子取整把弹出层的min_width同步为相同像素值使下拉面板与按钮等宽select_on_set_selectedobserver第 5 节所述的SetSelected转发。此外还有两个列表级 observerclose_popup_on_reselect 在收到ReselectListRow时隐藏弹出层“重复选择已选项”也会关闭面板。8. 小结FeathersSelect以“菜单按钮 弹出列表”的组合实现了完整的下拉选择字符串选项用list_rows_from_strings快速生成富数据选项可挂自定义组件并用max_visible控制滚动对外接口收敛为“实体上的ValueChangeEntity事件读 实体上的SetSelected事件写”与bevy_ui_widgets中SetChecked、SetSliderValue的编程式控制风格保持一致caption()补齐了控件内文字的 BSN 辅助函数让按钮、菜单、列表行等场景的文字声明更简洁。可直接参考的运行示例examples/ui/widgets/feathers_gallery.rs字符串与枚举两种选项风格和 examples/ui/layout/display_and_visibility.rs用下拉选项驱动目标实体状态更新的完整模式。【免费下载链接】bevyA refreshingly simple>项目地址: https://gitcode.com/GitHub_Trending/be/bevy创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考