快速入门
本章节将为你介绍 Ribir 的全部语法和常用的基本概念。
你将了解
- 如何创建和组合 widget
- 如何响应事件并操作数据
- 如何让视图自动响应数据变更
- 如何构建动态 widget
- 如何将自己的数据结构映射为视图
- 如何将内建 widget 当做其它 widget 的一部分来使用
- 如何对状态进行转换,分离和溯源——方便状态的传递和控制视图的更新范围
什么是 widget?
在 Ribir 中,widget 作为核心概念,它是对视图进行描述的基本单元。在形式上它可以是一个按钮,一个文本框,一个列表,一个对话框,甚至是整个应用界面。在代码上,它可以是一个函数,一个闭包或者一个数据对象。Ribir 将能通过 &BuildCtx
构建出 Widget
的类型叫做 widget。注意 Widget
和 widget 的差别,在整个 Ribir 的语境中,widget 是一个泛称,而大写开头的 Widget
是一个具体的 widget,也是所有 widget 构建进入视图的通行证。
如果你不是特别理解上面的话,不用在意,因为你完全不需要关注 widget 的构建过程,Ribir 也禁止干涉这个过程。你只需明白,Ribir 将所有的 widget 分成四类:
- 函数 widget
Compose
widgetRender
widgetComposeChild
widget
本章将只会介绍函数 widget 和 Compose
widget。因为在大部分场景中这两种 widget 已经足够满足我们的需求了。作为进阶的内容,我们将在深入 widget中覆盖 Render
widget 和 ComposeChild
widget。
函数 widget
接收 &BuildCtx
作为入参并返回 Widget
的函数或闭包被称为函数 widget。
在没有外部状态依赖的情况下,通过函数来定义 widget 是最简单的一种方式。在体验 Ribir中,你已经见过一个 Hello world!
的函数 widget 了。本节中,我们仍通过 Hello world!
的例子来展开介绍。
通过函数来定义 widget
直接通过函数来定义 widget:
use ribir::prelude::*;
fn hello_world() -> Widget<'static> {
rdl!{ Text { text: "Hello World!" } }
.into_widget()
}
fn main() {
App::run(hello_world);
}
rdl!{ Text { text: "Hello World!" } }
,通过 rdl!
创建了一个内容为 Hello World!
的 Text
。关于 rdl!
的细节,你可以先放到一边,将在小节 使用 rdl!
创建对象 中详细介绍。
最后,将 Text
通过 build
方法构建成 Widget
,作为函数的返回值。
小提示
Ribir 中有多个过程宏,而 &BuildCtx 常常作为一个需要跨宏使用的变量。为了简化这个传递过程 ,Ribir 在这样的情况下,统一使用
ctx!
来命名&BuildCtx
,以允许它跨宏使用。所以,你以后会经常看到ctx!
这个宏。
闭包和 fn_widget!
因为 hello_world
并没有被其它人调用,所以你可以将它改写成一个闭包:
use ribir::prelude::*;
fn main() {
let hello_world = || {
rdl!{ Text { text: "Hello World!" } }
.into_widget()
};
App::run(hello_world);
}
对于通过闭包创建函数控件,Ribir 提供了一个 fn_widget!
宏来简化这个过程,fn_widget!
除了支持我们本章接下来要讲到的两个语法糖 @
和 $
之外,你可以简单认为它会这样展开代码:
move || -> Widget {
{
// 你的代码
}
.into_widget()
}
使用 fn_widget!
改写 hello_world
例子:
use ribir::prelude::*;
fn main() {
App::run(fn_widget! {
rdl!{ Text { text: "Hello World!" } }
});
}
你有没有发现,除了没有使用 @
以外,这个例子和你在体验 Ribir中看到的已经一样了。
使用 rdl!
创建对象
rdl
是 Ribir Declarative Language 的缩写, rdl!
宏的目的就是帮助你以声明式的方式来创建对象。
注意
rdl!
并不关注类型,只在语法层面做处理,所以并不是只有 widget 才可以用它。
声明式创建对象
尽管 rdl!
支持任意 Rust 表达式,但我们所说的声明式创建对象,特指通过结构体字面量的方式。