#animation #iced #widgets #gui-applications #interface #depend

cosmic-time

Iced 和 Cosmic DE 的动画 Crate

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

MIT 许可证

170KB
4K SLoC

COSMIC TIME

Iced 设计的动画工具包

该项目是为 Cosmic DE 构建的。尽管这也可以适用于任何依赖 Iced 的项目。

该项目的目标是提供一个简单的 API,以在用 Iced-rs/Iced 构建的应用程序中高效地构建和显示复杂动画。

项目目标

  • 完全兼容 Iced 和 Elm 架构。
  • 易于使用。
  • 无需任何动画的数学知识。
  • 渲染循环中无堆分配。
  • 提供额外的可动画控件。
  • 自定义控件支持(创建自己的!)。

概述

要将 cosmic-time 集成到 Iced,需要进行以下五个步骤。

  1. 创建一个 Timeline。这是控制动画的类型。
struct Counter {
      timeline: Timeline
}

// ~ SNIP

impl Application for Counter {
    // ~ SNIP
     fn new(_flags: ()) -> (Self, Command<Message>) {
        (Self { timeline: Timeline::new()}, Command::none())
     }
}
  1. 将至少一个动画添加到您的时间轴中。这可以在您的应用程序的 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();

这段代码可以编译,但会导致动画不同步。

  1. 添加宇宙时间订阅
  fn subscription(&self) -> Subscription<Message> {
       self.timeline.as_subscription::<Event>().map(Message::Tick)
   }
  1. 将订阅映射到更新时间线的状态
fn update(&mut self, message: Message) -> Command<Message> {
       match message {
           Message::Tick(now) => self.timeline.now(now),
       }
   }

如果您跳过此步骤,您的动画将无法进行!

  1. 在您的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