4 个版本
0.2.0 | 2023 年 4 月 13 日 |
---|---|
0.1.2 | 2023 年 3 月 29 日 |
0.1.1 | 2023 年 3 月 28 日 |
0.1.0 | 2023 年 3 月 28 日 |
在 GUI 中排名第 535
170KB
4K SLoC
COSMIC TIME
为 Iced 设计的动画工具包
该项目的目标是提供一个简单的 API,以在用 Iced-rs/Iced 构建的应用程序中高效地构建和显示复杂动画。
项目目标
- 完全兼容 Iced 和 Elm 架构。
- 易于使用。
- 无需任何动画的数学知识。
- 渲染循环中无堆分配。
- 提供额外的可动画控件。
- 自定义控件支持(创建自己的!)。
概述
要将 cosmic-time 集成到 Iced,需要进行以下五个步骤。
- 创建一个
Timeline
。这是控制动画的类型。
struct Counter {
timeline: Timeline
}
// ~ SNIP
impl Application for Counter {
// ~ SNIP
fn new(_flags: ()) -> (Self, Command<Message>) {
(Self { timeline: Timeline::new()}, Command::none())
}
}
- 将至少一个动画添加到您的时间轴中。这可以在您的应用程序的
new()
或update()
中完成,或者两者都可以!
static CONTAINER: Lazy<id::Container> = Lazy::new(id::Container::unique);
let animation = chain![
CONTAINER,
container(Duration::ZERO).width(10),
container(Duration::from_secs(10)).width(100)
];
self.timeline.set_chain(animation).start();
这里有一些不同之处!
static CONTAINER: Lazyid::Container = Lazy::new(id::Container::unique);
Cosmic Time 使用 ID 来引用每个动画。我们导出自己的,但它们与 Iced 用于控件操作的 ID 完全相同。每个可动画控件都需要一个 ID。每个 ID 只能引用一个动画。
let animation = chain![
宇宙时间指的是我们构建动画的方式,将其称为Chain
。每个关键帧都像链条一样相互连接。宇宙时间API不会说“将宽度从10改为100”。我们定义每个状态,我们希望小部件具有的状态,例如在.width(10)
在Duration::ZERO
然后.width(100)
在Duration::from_secs(10)
。其中Duration
是上一个关键帧之后的时间。这就是我们为什么称之为链的原因。尽管如此,我们无法不通过所有先前关键帧而达到下一个状态。
self.timeline.set_chain(animation).start();
然后我们需要将动画添加到Timeline
。我们称之为.set_chain
,因为每个ID只能有一个链。如果我们用具有相同ID的不同动画set_chain
,则第一个将被替换。这实际上是一个功能,而不是错误!此外,您还可以一次设置多个动画:self.timeline.set_chain(animation1).set_chain(animation2).start()
.start()
这个函数调用非常重要,我们应该专门看看它。宇宙时间是原子的,给定任何给定时间的Timeline
,全局动画将完全相同。计算任何动画插值的值是全局的。我们使用.start()
来同步它们。假设您有两个同时运行的5秒动画。它们应该在同一时间结束,对吗?这完全取决于小部件认为动画应该何时开始。.start()
告诉所有挂起的动画在调用.start()
时开始。这保证了它们保持同步。重要!请确保在每个update()
调用中只调用一次.start()
。以下是不正确的!
self.timeline.set_chain(animation1).start();
self.timeline.set_chain(animation2).start();
这段代码可以编译,但会导致动画不同步。
- 添加宇宙时间订阅
fn subscription(&self) -> Subscription<Message> {
self.timeline.as_subscription::<Event>().map(Message::Tick)
}
- 将订阅映射到更新时间线的状态
fn update(&mut self, message: Message) -> Command<Message> {
match message {
Message::Tick(now) => self.timeline.now(now),
}
}
如果您跳过此步骤,您的动画将无法进行!
- 在您的
view()
中显示小部件!
anim!(CONTIANER, &self.timeline, contents)
全部完成!为了让宇宙时间工作,需要一点线路连接,但之后只需几行代码就能创建相当复杂的动画!看看乒乓球示例,看看如何只用几行代码就能实现一个完整的乒乓球游戏!
完成
- 动画渲染循环中没有堆分配
- 编译时类型保证,动画ID将与正确的动画和控件类型匹配。
- 可动画容器控件
- 循环动画
- 动画缓动
- 缓动测试
- 添加空间控件
- 添加按钮控件
- 添加行控件
- 添加列控件
- 添加切换按钮控件
- 使用 iced 0.8
- 使用 iced 0.8 的帧率订阅
- 添加不同动画缓动值的逻辑
- 文档
- 优化
as_subscription
逻辑 - 为动画添加暂停功能
- 懒关键帧。(可以使用上一个(活动或非活动)动画的位置来启动另一个动画的关键帧。)
待办事项
- 添加任意长度单位之间的容器和空间动画。例如:从 Length::Shrink 到 Length::Fixed(10.) 和/或从 Length::Fill 到 Length::Shrink。目前只支持固定长度 Length::Fixed(_).
- 添加
Cosmic
cargo 功能,以兼容 iced 和 System76 的临时分支。 - 检测低运动可访问性以禁用动画。
- 通用动画逻辑测试
- 通过 wasm-unknown-unknown 构建,在网络上工作
- 基于物理的动画
- 确定还需要在这个列表上添加什么
iced 版本到所需 cosmic-time 版本的映射。
iced 版本 | 所需的 cosmic-time 版本 |
---|---|
0.8 | 1.2 |
0.9 | 2.0 |
依赖关系
~11–29MB
~461K SLoC