深入了解 Widget
在 Ribir 中:
- 视图由 widget 作为基本单位构建。
- widget 之间通过纯组合的方式组成新的 widget。
Ribir 的独特之处在于它是通过纯组合的方式来组成新的 widget。
纯组合
当我们说纯组合时,意味着: widget 之间的父子关系并不涉及所有权,父 widget 通过 trait 来约定可以有子 widget,但并不拥有子 widget。
通常,其它框架的数据结构是这样的,父亲通过一个类似 children
的属性持有孩子:
struct Parent {
property: &'static str,
children: Vec<Child>,
}
struct Child {
property: &'static str,
}
let widget = Parent {
property: "parent",
children: vec![
Child { property: "child1" },
Child { property: "child2" },
],
};
而在 Ribir 中,数据结构却是类似这样的:
struct Parent {
property: &'static str,
}
struct Child {
property: &'static str,
}
let parent = Parent { property: "parent" };
let child1 = Child { property: "child1" };
let child2 = Child { property: "child2" };
let widget = MultiPair {
parent,
children: vec![child1, child2],
};
父 widget 和子 widget 之间是完全透明和独立的,我们并不将子 widget 添加到父 widget 中。
当然,这只是一个简化的例子。实际上,Ribir 的组合方式更加灵活,而且在实际使用中,你不会接触到 MultiPair
这样的中间数据结构。
这种组合方式的优点是,它产生的 widget 更小,更纯粹,更容易复用,可以根据需要进行组合。让我们以 Ribir 的内建 widget 为例来说明这一点。
在传统的 GUI 框架中,我们通常通过继承一个基础对象(或类似的方式)来获得一组常用的基础功能。这个基础对象通常包含许多属性,因此并不小。然而,在 Ribir 中,我们通过按需组合一组迷你的内建 widget 来实现这些功能。以 Opacity
为例,在 Ribir 中,它只有一个 f32
类型的属性。当你需要改变 widget 的透明度时,你可以直接使用 Opacity
来组合你的 widget:
use ribir::prelude::*;
// Opacity 的定义是这样的:
// struct Opacity { opacity: f64 }
let w = Opacity { opacity: 0.5 }.with_child(Void, ctx);
当然,实际代码中,你可以直接写成 @Void { opacity: 0.5 }
。
四种基础 widget
即将推出
- render widget
- compose widget
- compose child widget
- function widget