欢迎光临
我们一直在努力

【Xilem0.4基础语法学与练】第28课 button 通用按钮组件

前言

文档参考:https://docs.rs/xilem/latest/xilem/view/fn.button.html
版本:Xilem 0.4

一、button基础概念

button 是通用可自定义内容按钮组件,按钮内部可以放置任意非交互式视图:label、flex、sized_box、z_stack等布局组合都可以作为按钮内容。

  • text_button = button(label(文本), 回调) 的简写,只能放纯文本。
  • button 自由度更高,支持图标+文字、多行、复杂排版的按钮。
  • 交互:鼠标左键点击触发回调;获得键盘焦点后,按 Space空格 / Enter回车 同样触发点击,键盘无障碍支持内置,不可修改快捷键。
  • 如果需要监听鼠标中键、右键、触摸事件,请使用 button_any_pointer 。

重要限制:

button内部禁止嵌套另一个button、text_button这类交互式控件,会产生鼠标焦点抢占、交互异常问题;内部只能放纯展示布局原语和label。

引入头

use xilem::view::{button, text_button, label, flex_col, flex_row, sized_box};
use xilem::{FontWeight, palette};

二、函数签名

pub fn button<State, Action, V: WidgetView<State, Action>>(
child: V,
callback: impl Fn(&mut State) -> Action + Send + 'static,
) -> Button<impl Fn(&mut State, Option<PointerButton>) -> MessageResult<Action> + Send + 'static, V>

  • child:按钮内部子视图,只能是非交互视图(label / flex / sized_box)
  • callback:点击回调,接收 &mut State ,修改应用状态。

基础最简示例

// 普通自定义按钮,内部加粗文本
let content = label("增加计数").weight(FontWeight::BOLD);
button(content, |state: &mut AppState| {
state.count += 1;
})

复杂内容:flex_row组合(文字+符号)

let inner = flex_row((
label("👍"),
label("点赞").weight(FontWeight::BOLD),
));
button(inner, |_state: &mut AppState| {})

三、button、text_button、button_any_pointer三者对比

  • button(child, callback)
    通用按钮,内部可嵌套布局;左键、空格、回车触发;不区分鼠标按键。
  • text_button(text, callback)
    简写:等价 button(label(text), callback) ;只能放纯文本,写法简洁。
  • button_any_pointer(child, callback)
    可以拿到鼠标按键信息(左键/中键/右键),回调参数携带 Option ,适合需要区分不同鼠标按键的场景。
  • 四、按钮样式的两种方式

    方式1:button自带链式样式

    button实例自带 .background_color() 、 .corner_radius() 、 .border_color() 、 .hovered_border_color() ,直接修改按钮本身外观。

    button(label("蓝色按钮"), |s:&mut AppState| s.count +=1)
    .background_color(palette::css::DODGER_BLUE)
    .corner_radius(10.0)
    .border_color(palette::css::TRANSPARENT);

    方式2:外层包sized_box修改尺寸

    button本身会跟随内部内容大小;想要固定宽高、整行铺满,外层套 sized_box 。

    sized_box(
    button(label("整行大按钮"), |_|{})
    ).expand_width()

    注意:
    sized_box 控制尺寸;button链式方法控制按钮背景、圆角;不要混淆两者职责。

    五、完整可运行示例

    Cargo.toml

    [package]
    name = "xilem_lesson28"
    version = "0.1.0"
    edition = "2021"

    [dependencies]
    xilem = "0.4.0"
    winit = "0.30"

    src/main.rs

    use xilem::palette;
    use xilem::winit::error::EventLoopError;
    use xilem::view::{button, flex_row, label, sized_box, text_button};
    use xilem::{EventLoop, FontWeight, WidgetView, WindowOptions, Xilem};

    #[derive(Default)]
    struct AppState {
    count: i32
    }

    fn app_logic(state: &mut AppState) -> impl WidgetView<AppState> + use<> {
    flex_row((
    // text_button简写,纯文本按钮
    text_button("-1", |s:&mut AppState| s.count -= 1),

    // 通用button,内部加粗label
    button(label(format!("计数:{}", state.count)).weight(FontWeight::BOLD), |_|{})
    .background_color(palette::css::LIGHT_GRAY)
    .corner_radius(6.0),

    // button内部放flex_row实现符号+文字
    button(
    flex_row((label("➕"), label("+1"))),
    |s:&mut AppState| s.count +=1
    )
    .background_color(palette::css::SKY_BLUE)
    .corner_radius(8.0),

    // sized_box包裹,固定尺寸按钮
    sized_box(
    button(label("归零"), |s:&mut AppState| s.count =0)
    .background_color(palette::css::ORANGE_RED)
    .corner_radius(8.0)
    ).width(80.px()).height(36.px()),
    ))
    }

    fn main() -> Result<(), EventLoopError> {
    let app = Xilem::new_simple(AppState::default(), app_logic);
    app.run(EventLoop::with_user_event(), WindowOptions::default())
    }

    六、高频踩坑清单

  • button内部不能嵌套button/text_button,会交互错乱;内部只能是label、flex、sized_box这类纯展示视图。
  • button 本身大小跟随内部子视图;想要固定宽高、expand铺满,必须外层套 sized_box 。
  • 键盘触发条件:按钮需要获得焦点,Tab切换焦点后按Space/Enter触发;快捷键不可自定义。
  • text_button 只是简写,适合简单文本;复杂排版(图标+文字、多行)必须使用 button 。
  • button的 .background_color() 、 .corner_radius() 属于button的链式方法,不是sized_box的;不要写在label上。
  • 如果需要监听鼠标右键、中键,请使用 button_any_pointer ,普通button回调拿不到鼠标按键信息。
  • 不要把交互业务逻辑写在子视图闭包,点击修改状态全部写在button的callback闭包。
  • 七、课后练习题

    仅使用本课 button ,搭配label、flex_row、sized_box;禁止嵌套button。

    练习1(基础)

    创建一个button,内部flex_row包含 label(“🔔”) 和加粗 label(“提醒”) ;设置按钮背景色 palette::css::GOLD ,圆角半径6;点击回调修改state.count+1。

    参考答案

    button(
    flex_row((
    label("🔔"),
    label("提醒").weight(FontWeight::BOLD)
    )),
    |s:&mut AppState| s.count += 1
    )
    .background_color(palette::css::GOLD)
    .corner_radius(6.0)

    练习2(进阶)

    外层flex_row横向布局:

  • 左侧练习1自定义button;
  • 中间 text_button(“重置”,|_|{}) ;
  • 右侧用sized_box包裹button,expand_width占满剩余空间,内部label文本 填充按钮 。
  • 参考答案

    flex_row((
    button(
    flex_row((label("🔔"), label("提醒").weight(FontWeight::BOLD))),
    |s:&mut AppState| s.count += 1
    ).background_color(palette::css::GOLD).corner_radius(6.0),

    text_button("重置", |s:&mut AppState| s.count =0),

    sized_box(
    button(label("填充按钮"), |_|{})
    .background_color(palette::css::LIGHT_BLUE)
    ).expand_width()
    ))

    练习3(拓展)

    flex_col纵向布局:

  • 顶部sized_box.expand_width,放一个button;
  • 按钮内部使用z_stack叠加两层label;
  • 点击按钮让count自增。
  • 参考答案片段

    flex_col((
    sized_box(
    button(
    z_stack((
    label("底层文字"),
    label("上层叠加文字").weight(FontWeight::BOLD)
    )),
    |s:&mut AppState| s.count += 1
    )
    .background_color(palette::css::ALICE_BLUE)
    .corner_radius(10.0)
    ).expand_width()
    ))

    八、知识点总结

  • button(child, callback) 通用按钮,内部支持任意非交互视图; text_button 是纯文本简写。
  • 鼠标左键、键盘Space/Enter(获得焦点)都会触发button回调;监听多鼠标按键用 button_any_pointer 。
  • button内部严禁嵌套另外的交互式按钮,会导致焦点抢占交互异常。
  • button自带 .background_color() 、 .corner_radius() 等链式样式;尺寸控制交给外层 sized_box 。
  • 复杂按钮(图标+文字、叠加文字):把flex_row/z_stack/sized_box作为button的child参数传入。
  • 点击业务逻辑写在第二个回调闭包,修改AppState状态,框架自动重渲染UI。
  • 赞(0)
    未经允许不得转载:171主机测评 » 【Xilem0.4基础语法学与练】第28课 button 通用按钮组件
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址