EUI-NEO

动画系统

EUI-NEO 技术文档。

动画系统

动画系统位于 core/animation.h,并由 core::dsl::Runtime 接入 DSL。页面和组件只声明目标状态,Runtime 负责插值、重绘节奏和脏区标记。

核心类型

enum class Ease {
    Linear,
    InQuad,
    OutQuad,
    InOutQuad,
    OutCubic,
    InOutCubic,
    OutBack
};
struct Transition {
    bool enabled;
    float durationSeconds;
    float delaySeconds;
    Ease ease;
    AnimProperty properties;
};
template <typename T>
class AnimatedValue;

template <typename T>
class SmoothedValue;

DSL 写法

ui.rect("actor")
    .x(active ? 420.0f : 40.0f)
    .opacity(active ? 0.42f : 1.0f)
    .rotate(active ? 0.36f : 0.0f)
    .transition(0.42f, core::Ease::OutBack)
    .build();

也可以传完整 transition:

core::Transition t = core::Transition::make(0.24f, core::Ease::OutCubic)
    .animate(core::AnimProperty::Color | core::AnimProperty::Opacity);

ui.rect("panel")
    .color(nextColor)
    .opacity(nextOpacity)
    .transition(t)
    .build();

可动画属性

Rect

Text

Hover / Press 动画

交互矩形通过 states 开启:

ui.rect("button.bg")
    .states(normal, hover, pressed)
    .onClick(callback)
    .build();

Runtime 会维护:

颜色混合路径:

normal -> hover -> pressed

按钮按压缩放通过 visualStateFrom 共享某个交互 rect 的 press 状态:

ui.stack("button")
    .size(w, h)
    .visualStateFrom("button.bg", 0.965f)
    .content([&] {
        ui.rect("button.bg")
            .size(w, h)
            .states(normal, hover, pressed)
            .build();
    });

动画与 compose

动画不是通过每帧改 DSL 树实现的。

推荐模式:

1. app 状态改变。 2. compose 声明新的目标属性。 3. Runtime 发现目标值变化。 4. AnimatedValue<T> 从当前值插到新目标值。 5. 每帧只标记相关 dirty rect。

hover / press 是 Runtime 内部状态变化,不会触发重新 compose。

click 回调可能修改 app 状态,所以 Runtime 会设置 needsCompose()app/dsl_app.h 再重新 compose。

动画与脏区

动画推进时,Runtime 会计算:

dirty = union(oldVisualRect, newVisualRect)

Rect,visual rect 会考虑:

Text,dirty rect 使用文本 frame。

然后 Runtime 使用 framebuffer cache + scissor 只重绘脏区。

当前限制