尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

gpui-kit 按钮组件实战指南:Button / ButtonGroup 的变体、图标、状态与自定义方案

gpui-kit 按钮组件实战指南:Button / ButtonGroup 的变体、图标、状态与自定义方案 gpui-kit 按钮组件实战指南Button / ButtonGroup 的变体、图标、状态与自定义方案【免费下载链接】gpui-kitRust GUI components for building fantastic cross-platform desktop application by using GPUI.项目地址: https://gitcode.com/GitHub_Trending/gp/gpui-kit导读本文是 gpui-kit基于 GPUI 的跨平台 Rust 桌面 UI 组件库中Button组件的完整技术指南。围绕 website/component/button.md 展开并结合 button 模块源码 与官方 story 演示系统讲解按钮的 9 种语义变体、4 档尺寸、图标体系Icon / Spinner / ProgressCircle、disabled/loading/selected三种状态、按钮组单选多选逻辑、自定义变体与无障碍细节。读完本文你将能够在一行链式调用中构建出满足桌面端视觉与交互要求的任意按钮并理解其底层样式解析与事件拦截原理。引入与依赖Button及其配套的ButtonGroup位于gpui_kit组件层的 button 子模块模块声明见 mod.rs实际实现分布在button.rsButton核心元素、ButtonVariant、ButtonCustomVariant、ButtonVariantstraitbutton_group.rsButtonGroup分组元素button_icon.rsButtonIcon与ButtonIconVariant图标自动切换机制dropdown_button.rs 与 toggle.rs下拉按钮与开关按钮的配套实现。在代码中按如下方式导入即可use gpui_kit::component::button::{Button, ButtonGroup};若需要自定义变体再追加use gpui_kit::component::button::ButtonCustomVariant;基础用法Button::new接受一个ElementId任意可转换为impl IntoElementId的类型之后通过链式方法组装外观与行为Button::new(my-button) .label(Click me) .on_click(|_, _, _| { println!(Button clicked!); })on_click的回调签名为Fn(ClickEvent, mut Window, mut App)button.rsClickEvent区分鼠标与键盘触发见下文测试部分。从 button_story.rs 可以看到官方演示中把点击与悬停处理器定义为静态方法复用fn on_click(ev: ClickEvent, _: mut Window, _: mut App) { println!(Button clicked {:?}, ev); } fn on_hover(hovered: bool, _: mut Window, _: mut App) { println!(Button hovered {:?}, hovered); }on_hover的布尔参数表示指针是否悬停在按钮上仅在按钮可交互未禁用、未加载且注册了该回调时才生效。变体VariantsButton通过ButtonVariantstrait 暴露语义化变体button.rs每个变体对应ButtonVariant枚举中的一员并由with_variant统一写入// Primary button Button::new(btn-primary).primary().label(Primary) // Secondary button显式调用默认值见下 Button::new(btn-secondary).secondary().label(Secondary) // Danger button Button::new(btn-danger).danger().label(Delete) // Warning button Button::new(btn-warning).warning().label(Warning) // Success button Button::new(btn-success).success().label(Success) // Info button Button::new(btn-info).info().label(Info) // Ghost button Button::new(btn-ghost).ghost().label(Ghost) // Link button Button::new(btn-link).link().label(Link) // Text button Button::new(btn-text).text().label(Text)ButtonVariant枚举定义button.rs中Default被标记为#[default]——即不调用任何变体方法时的默认外观其背景取自主题 tokenbutton边框色为input前景色为button_foreground。各变体的视觉差异在ButtonVariant::normal / hovered / active / selected / disabled五个样式中解析button.rs全部消费自ActiveTheme/ theme tokens因此换主题即可整体换肤。几点值得注意的语义细节Ghost背景恒为transparent悬停/按下时使用secondary颜色按明暗模式进行lighten/darken处理后叠加透明度Link无内边距no_padding、默认带下划线underline true角色为Role::Link前景色为link悬停为link_hover、按下为link_activeText同样无内边距看起来像普通文字前景色为foreground.opacity(0.9)悬停恢复foreground按下降为opacity(0.7)ButtonVariant::is_link() / is_text() / is_ghost()提供了快速判断button.rs其中no_padding()直接决定渲染时是否跳过内边距计算。Outline描边风格outline不是独立变体而是一个可以与任意变体叠加的修饰位self.outline true见 button.rsButton::new(btn).primary().outline().label(Primary Outline) Button::new(btn).danger().outline().label(Danger Outline)从样式解析看button.rsoutline 模式的背景使用语义色 token 的低透明度版本normal 0.1 → hover 0.2 → active 0.4边框使用语义色本身对于Default变体则退化为input_background。源码测试test_outline_primary_keeps_original_depth与test_outline_buttons_use_semantic_gradient_tokensbutton.rs验证了 outline 按钮在渐变主题下仍保持语义色低透明度背景。尺寸与紧凑模式Button实现了Sizabletrait支持Size枚举sizing.rs中的四档标准尺寸与自定义像素值Button::new(btn).xsmall().label(Extra Small) Button::new(btn).small().label(Small) Button::new(btn).label(Medium) // 默认 Button::new(btn).large().label(Large)Size::Medium是默认值#[default]。渲染时具体尺寸映射button.rs图标按钮无 label 无 childrenxsmall → size_5、small → size_6、medium/large → size_8自定义Size::Size(px)直接使用该像素值常规按钮xsmall → h_5 px_1、small → h_6 px_2、medium → h_8 px_2p5、large → h_8 px_3自定义尺寸px(size * 0.2)作为水平内边距图标尺寸自动适配渲染时若为自定义尺寸图标按size * 0.75缩放button.rsSize还提供smaller() / larger()递进方法便于派生。compact方法减少内边距让按钮更紧凑Button::new(btn) .label(Compact) .compact()紧凑模式在各档位上的实际效果button.rsxsmall增加min_w_5small内边距降为px_1p5并加min_w_6medium/large内边距降为px_2并加min_w_8。图标体系icon方法接受impl IntoButtonIcon而ButtonIconVariant提供三种转换button_icon.rs[Icon] / [IconName]静态图标用于动作与视觉提示[Spinner]旋转加载指示器用于异步操作[ProgressCircle]环形进度展示完成百分比。这些图标类型都会自动适配按钮尺寸Sizable实现见 button_icon.rs并可通过颜色等属性进一步定制。基础图标use gpui_kit::component::{Icon, IconName}; // 直接使用 IconName最简形式 Button::new(btn) .icon(IconName::Check) .label(Confirm) // 使用 Icon 自定义尺寸 Button::new(btn) .icon(Icon::new(IconName::Heart)) .label(Like) // 仅图标、无 label自动进入 Icon Button 模式 Button::new(btn) .icon(IconName::Search)不设置label且无子元素时按钮自动变为正方形图标按钮尺寸映射见上文button.rs。Spinner 图标use gpui_kit::component::spinner::Spinner; // 基础 spinner Button::new(btn) .icon(Spinner::new()) .label(Loading...) // 自定义颜色 Button::new(btn) .icon(Spinner::new().color(cx.theme().blue)) .label(Processing) // 自定义旋转图标 Button::new(btn) .icon(Spinner::new().icon(IconName::LoaderCircle)) .label(Syncing)ProgressCircle 图标use gpui_kit::component::progress::ProgressCircle; // 基础进度环value 为百分比数值 Button::new(btn) .icon(ProgressCircle::new(install-progress).value(45.0)) .label(Installing...) // 与主按钮变体组合、自定义颜色 Button::new(btn) .primary() .icon( ProgressCircle::new(download-progress) .value(75.0) .color(cx.theme().primary_foreground) ) .label(Downloading) // 不同尺寸 Button::new(btn) .small() .icon(ProgressCircle::new(progress-1).value(60.0)) .label(Installing...) Button::new(btn) .large() .icon(ProgressCircle::new(progress-2).value(80.0)) .label(Installing...)ProgressCircle::new同样需要传入元素 id源码测试中ProgressCircle::new(75)也接受数值形式见 button_icon.rs。动态更新图标图标可以随组件状态在渲染期动态切换struct InstallButton { progress: f32, is_installing: bool, } impl InstallButton { fn render(mut self, _: mut Window, cx: mut ContextSelf) - impl IntoElement { let button Button::new(install-btn) .label(if self.is_installing { Installing... } else { Install }); if self.is_installing { button.icon( ProgressCircle::new(install-progress) .value(self.progress) ) } else { button.icon(IconName::Download) } } }配合cx.notify()即可在安装进度更新时重绘图标与百分比。加载态的图标切换机制当按钮处于加载态时ButtonIcon::render会自动决定显示哪个图标button_icon.rs若原图标已经是 Spinner 或 ProgressCircle加载时保持原样显示进度环继续展示进度若原图标是普通 Icon加载时自动替换为Spinner可通过loading_icon指定替换用的图标。// 图标已是 Spinner 或 ProgressCircle加载时继续显示 Button::new(btn) .icon(Spinner::new()) .label(Processing) .loading(true) // Spinner 继续显示 // 普通图标加载时自动替换为 Spinner Button::new(btn) .icon(IconName::Save) .label(Saving) .loading(true) // 图标被替换为 Spinner自定义加载图标Button::new(btn) .icon(IconName::Plus) .loading_icon(IconName::Loader) // loadingtrue 时用 Loader 替换 Plus .loading(true) .label(Creating)下拉箭头.dropdown_caret(true)在按钮末尾追加一个下拉箭头复用select::Caret颜色为前景色 75% 透明度Button::new(btn) .label(Options) .dropdown_caret(true)源码中当同时存在图标/标签/子内容时内容区域会切换为justify_between布局button.rs。该能力常与DropdownButtondropdown_button.rs或 PopupMenu 组合使用例如 button_story.rs 中button(button-options).label(Options)作为工具栏下拉触发器。状态States按钮拥有disabled、loading、selected三种状态// Disabled不可交互采用禁用样式 Button::new(btn) .label(Disabled) .disabled(true) // Loading不可交互但保持自身变体样式整体 80% 透明度 Button::new(btn) .label(Loading) .loading(true) // Selected选中样式常用于 toggle/分组场景 Button::new(btn) .label(Selected) .selected(true)disabled来自Disableabletraitbutton.rsselected来自Selectabletraitbutton.rs。底层语义值得展开interactive()定义为!(disabled || loading)button.rs它统一门控了 hover/active 样式、link 按钮的手型光标与mouse_down处理。也就是说加载中的按钮与禁用按钮同样惰性只是外观保持自身变体而非禁用样式渲染时对loading !disabled的按钮整体施加opacity(0.8)button.rs并在mouse_down与on_click中调用cx.stop_propagation()阻断事件继续冒泡到父级。这一点被 button.rs 测试 明确验证loading_button_keeps_existing_pointer_blocking、loading_button_without_callback_still_blocks_parent_activation均断言加载按钮被点击、被 Enter/Space 触发后自身与父容器回调计数保持为 0。无障碍状态selected(true)只影响选中样式不会自动把按钮宣布为开关toggle。若按钮确实是一个切换控件需要额外调用.toggled(bool)设置 accesskit 的 pressed 状态button.rs源码测试selected_trigger_presentation_does_not_imply_toggled_accessibilitybutton.rs专门守护了这一语义。ButtonGroup内部的子按钮则会自动带上toggled(selected)元数据button_group.rs。按钮组ButtonGroupButtonGroup用于把多个按钮组合成一个整体控件自动处理相邻按钮的边框合并与圆角衔接ButtonGroup::new(btn-group) .child(Button::new(btn1).label(One)) .child(Button::new(btn2).label(Two)) .child(Button::new(btn3).label(Three))切换式按钮组ButtonGroup::new(toggle-group) .multiple(true) // 允许多选 .child(Button::new(btn1).label(Option 1).selected(true)) .child(Button::new(btn2).label(Option 2)) .child(Button::new(btn3).label(Option 3)) .on_click(|selected_indices, _, _| { println!(Selected: {:?}, selected_indices); })on_click回调第一个参数是选中按钮索引向量Vecusizebutton_group.rs例如[0, 2, 3]表示第 1、3、4 个按钮被选中multiple(false)默认单选每次点击只保留当前索引multiple(true)多选点击已选中项会从向量中移除toggle 行为。官方注释里给出一个典型的尺寸选择器用法button_group.rs根据clicks.contains(0/1/2)分别把状态设为Size::Large / Medium / Small后cx.notify()。分组属性透传与布局ButtonGroup自身实现Disableable、Sizable、Styled、ButtonVariants并会把size、variant、compact、outline、disabled透传给每个子按钮button_group.rs.compact()/.outline()/.primary()等方法作用于整组.layout(Axis::Vertical)切换为垂直排布默认Axis::Horizontalbutton_group.rs渲染时按首/中/尾位置裁剪圆角首按钮左上圆角、尾按钮右下圆角等实现无缝衔接的分段控件button_group.rs。测试test_button_group_builderbutton_group.rs验证了分组属性组合的正确性legacy_single_and_multiple_results_use_the_rendered_selectionbutton_group.rs则验证多选模式下索引向量的追加顺序。自定义变体ButtonCustomVariant内置变体覆盖不了品牌色时可用ButtonCustomVariant完全自定义配色use gpui_kit::component::button::ButtonCustomVariant; let custom ButtonCustomVariant::new(cx) .color(cx.theme().magenta) // 背景色默认 transparent .foreground(cx.theme().primary_foreground) // 前景色默认主题 foreground .border(cx.theme().magenta) // 边框色 .hover(cx.theme().magenta.opacity(0.1)) // 悬停背景色默认 transparent .active(cx.theme().magenta); // 按下背景色默认 transparent Button::new(custom-btn) .custom(custom) .label(Custom Button)ButtonCustomVariant结构体button.rs持有color / foreground / shadow / hover / active五个字段各 setter 的默认值见 button.rs背景、悬停、按下默认均为transparent前景默认主题foregroundshadow默认false开启后渲染shadow_xs。自定义变体同样支持outline()叠加outline 模式下背景与边框会与白色混合 40%。官方 story 中即使用 magenta 主题色构造了自定义按钮button_story.rs。圆角与边框控制ButtonRounded枚举button.rs控制圆角None无圆角Smallradius * 0.5Medium默认radiusLargeradius * 2Size(Pixels)自定义像素值impl FromPixels。Button::new(btn).rounded(ButtonRounded::Small).label(Rounded)圆角值取自cx.theme().radius跟随主题变化。按钮组在内部通过border_corners/border_edges精细控制每一边这两个方法是 crate 内部接口供分组衔接使用。Tooltip 提示按钮可直接挂载 tooltip并可选指定首选方位Button::new(btn) .label(Hover me) .tooltip(This is a helpful tooltip) .tooltip_placement(Placement::Bottom).tooltip(...)设置提示文本.tooltip_placement(...)为.tooltip(...)或.tooltip_with_action(...)指定首选方位空间不足时仍会自动翻转不调用则保持自动定位button.rs.tooltip_with_action(tooltip, action, context)提示中附带快捷键显示action为 GPUI action、context为可选的 action 上下文button.rs。渲染时通过managed_tooltip_with_placement挂载button.rstooltip 内容可带action展示快捷键。自定义子内容按钮内容不限于文字可以放入任意 GPUI 元素Button::new(btn) .child( h_flex() .items_center() .gap_2() .child(Custom Content) .child(IconName::ChevronDown) .child(IconName::Eye) )Button实现了ParentElementbutton.rs因此可以.child(...)挂任意子元素同时实现Styled与InteractiveElement支持直接链式调用.size_full()、.w_full()、.flex_1()等样式方法story 中大量使用例如 alert_dialog_story.rs 的.flex_1().outline().label(Cancel)。当按钮同时有 label 与自定义 children 时两者都会渲染见测试base_slot_prepaints_complete_button_contentbutton.rs。键盘交互与无障碍按钮的键盘可访问性由以下方法支持tab_index(isize)/tab_stop(bool)默认tab_index 0、tab_stop true控制 Tab 聚焦行为button.rsfocus_ring(bool)聚焦时显示焦点环默认开启通过FocusableExt提供accessibility_id(...)向无障碍客户端暴露开发者指定的标识accessibility_label(...)当可见内容不适合朗读时典型如纯图标按钮、整行按钮用显式名称替换屏幕阅读器读出的名字button.rs。源码测试an_explicit_accessibility_label_replaces_the_visible_onebutton.rs验证了显式名称优先于可见 label且不改变绘制内容role(...)Link变体默认角色为Role::Link其余为Role::Buttonbutton.rs。键盘事件方面测试enabled_button_delegates_pointer_enter_and_space_oncebutton.rs确认 Enter 与 Space 都能触发ClickEvent::Keyboard点击且只触发一次同时焦点被正确接管。源码级验证测试与 Story 演示单元测试button 模块内置多组测试可作为行为契约参考事件拦截禁用/加载按钮均阻断点击与键盘触发且不向父级冒泡button.rs主题 token验证渐变主题下 primary 背景使用button.primary.background等 tokenbutton.rsoutline 语义outline 按钮使用语义色低透明度背景而非实心色button.rs按钮组分组回调覆盖子按钮回调、单选/多选索引正确性、键盘点击不触发分组回调button_group.rs图标变体ButtonIconVariant三种类型判定与自定义 data 图标的转换button_icon.rs。官方 Story完整的交互演示见 button_story.rs它把disabled / loading / selected / compact / shadow / multiple做成工具栏开关实时切换整页按钮的状态同时还演示了通过ChangeStorySize在四档尺寸间切换、自定义 magenta 变体以及Options下拉按钮。运行 story 应用crates/storycrate即可直接观察每种变体在不同状态下的视觉效果是学习本组件最快的途径。小结与 API 速查能力方法源码位置变体primary/secondary/danger/warning/success/info/ghost/link/text/custombutton.rs描边outline()button.rs尺寸xsmall/small/largeSizablesizing.rs紧凑compact()button.rs图标icon(Icon/IconName/Spinner/ProgressCircle)button_icon.rs加载图标loading_icon(Icon)button.rs状态disabled/loading/selectedbutton.rs下拉箭头dropdown_caret(bool)button.rsTooltiptooltip/tooltip_placement/tooltip_with_actionbutton.rs自定义变体ButtonCustomVariant::new(cx)button.rs分组ButtonGroupmultiple/layout/on_clickbutton_group.rs构建按钮时的基本心法先选变体语义→ 再定尺寸与紧凑度空间→ 决定图标内容信息→ 配置状态与交互行为→ 需要时叠加 tooltip、无障碍信息与自定义配色。所有配置均为声明式链式调用且样式全部消费主题 token配合 themes 目录 下的主题文件即可让整套按钮体系随主题一键切换。【免费下载链接】gpui-kitRust GUI components for building fantastic cross-platform desktop application by using GPUI.项目地址: https://gitcode.com/GitHub_Trending/gp/gpui-kit创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表