feat(motion2): 右栗折叠过渡 + 状态层 hover/pressed 过渡
A2 侧边栏(右栗 AI 栏)折叠/展开: - 帧泵第三条轨道(pump/rail):展开 medium1 250ms + Emphasized、收起 short4 200ms + EmphasizedAccelerate;拆出档走 snap(不做过渡);MotionScale::NONE 下不插轨道 - 宽度在 metrics::rail_width 逐帧插值;面板内容按目标宽排版 + 按动画宽裁切 (不重排 / 不溢出),宽度回到 48 时换成图标条(图标贴右端,位置不跳) - pages/agent/mod.rs 的展开档面板纯搬移到 panel.rs(371 → 289 行) A8 状态层过渡: - interaction/layer:令牌化的进度时钟(short1 50ms),NONE 当帧落终值 - interaction/hover:取样控件把起跑搬到 Widget::update(早于订阅表求值) - 按钮五式 + IconButton + 导航项药丸统一走 interaction::layer_color (没有取样控件时逐位退回旧口径,出图基线不变) - components/motion/mod.rs 的 needs_frames / advance 各加一句委托, 帧订阅仍然只有一处判断点(app/subscription.rs 未改)
This commit is contained in:
1 parent
c4706c759c
commit
b61f342431
22 files changed
+1837
-145
No files matched your search
@@ -10,17 +10,20 @@
|
||||
//! |---|---|---|
|
||||
//! | 页面 | 内容标识变了([`Pump::observe`]) | 两腿里长的那条走完 |
|
||||
//! | 模态 | 弹窗开 / 关([`Pump::observe_modal`] / [`Pump::begin_modal_close`]) | 进场转 [`Modal::Open`](**不再要帧**)、退场转 [`Modal::Hidden`] |
|
||||
//! | 折叠(M257) | 右栗档位变([`Pump::observe_rail`],拆出档走 [`Pump::snap_rail`]) | 主进度走完一条腿(`medium1` / `short4`) |
|
||||
//!
|
||||
//! D31:时长/缓动是**表**([`super::transition`]),页面只许按表取——它只能说「我要换页了」。
|
||||
|
||||
use unlucky_design::motion::{DurationToken, MotionScale};
|
||||
|
||||
mod modal;
|
||||
mod rail;
|
||||
|
||||
use super::transition::{
|
||||
enter_offset, exit_offset, modal_spec, page_spec, Kind, PageFrame, PageSpec,
|
||||
};
|
||||
pub(crate) use modal::Modal;
|
||||
pub(crate) use rail::RailTrack;
|
||||
|
||||
/// 逐帧**推进时间轴**的最短间隔(16 ms ≈ 60 次/秒)。
|
||||
///
|
||||
@@ -61,6 +64,10 @@ pub struct Pump {
|
||||
pending_ms: f64,
|
||||
page: Option<PageTrack>,
|
||||
modal: Modal,
|
||||
/// 右栗折叠轨道(M257):`Some` = 宽度正在 `48 ⇄ 展开档` 之间走。
|
||||
rail: Option<RailTrack>,
|
||||
/// 右栗的目标档(`true` = 展开)。没有轨道时进度就是它的终值。
|
||||
rail_open: bool,
|
||||
/// 退场走完了、等调用方真正关掉那个框([`Pump::take_modal_closed`] 取走一次)。
|
||||
close_pending: bool,
|
||||
screen: Option<u64>,
|
||||
@@ -81,6 +88,8 @@ impl Pump {
|
||||
pending_ms: 0.0,
|
||||
page: None,
|
||||
modal: Modal::Hidden,
|
||||
rail: None,
|
||||
rail_open: false,
|
||||
close_pending: false,
|
||||
screen: None,
|
||||
rank: None,
|
||||
@@ -104,6 +113,9 @@ impl Pump {
|
||||
self.detail = None;
|
||||
self.pending_ms = 0.0;
|
||||
self.modal = Modal::Hidden;
|
||||
// 定档时右栗按出厂档(收起)复位:定档之后的第一帧画的就是 48,不会先画一次展开态。
|
||||
self.rail = None;
|
||||
self.rail_open = false;
|
||||
self.close_pending = false;
|
||||
if scale.is_off() {
|
||||
// 关掉动效 = 直接落终态:把在跑的轨道清掉,而不是让它跑一遍 0 时长。
|
||||
@@ -129,7 +141,9 @@ impl Pump {
|
||||
|
||||
/// 现在有没有动画在跑(= 要不要订阅帧)。
|
||||
pub fn is_animating(&self) -> bool {
|
||||
self.page.is_some() || matches!(self.modal, Modal::Opening { .. } | Modal::Closing { .. })
|
||||
self.page.is_some()
|
||||
|| self.rail.is_some()
|
||||
|| matches!(self.modal, Modal::Opening { .. } | Modal::Closing { .. })
|
||||
}
|
||||
|
||||
/// 轨道起点的口径:钉住相位时恒为 0(进度只取决于钉住值,与"谁在第几帧起跑"无关)。
|
||||
@@ -286,6 +300,11 @@ impl Pump {
|
||||
self.page = None;
|
||||
}
|
||||
}
|
||||
if let Some(track) = self.rail {
|
||||
if now - track.start_ms >= track.duration_ms {
|
||||
self.rail = None;
|
||||
}
|
||||
}
|
||||
let spec = modal_spec();
|
||||
match self.modal {
|
||||
Modal::Opening { start_ms } if now - start_ms >= self.leg_ms(spec.enter.duration) => {
|
||||
|
||||
Reference in new issue
Block a user