Enhaced m3 motion
This commit is contained in:
parent
758869920c
commit
b2c3202317
|
|
@ -786,13 +786,11 @@ class _M3ErrorShakeState extends State<M3ErrorShake>
|
||||||
// M3BounceIcon — entrance + idle pulse for empty/error states
|
// M3BounceIcon — entrance + idle pulse for empty/error states
|
||||||
// ═══════════════════════════════════════════════════════════════
|
// ═══════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
/// Displays an [icon] inside a colored circular badge with:
|
/// Displays an [icon] inside a colored circular badge with a spring-bounce
|
||||||
/// 1. A spring-bounce entrance animation on first build.
|
/// entrance animation: scales from 0 → 1.0 with a slight overshoot.
|
||||||
/// 2. A slow, gentle idle pulse (scale 1.0 → 1.06 → 1.0) that repeats
|
|
||||||
/// indefinitely to draw attention without being distracting.
|
|
||||||
///
|
///
|
||||||
/// Respects [m3ReducedMotion] — both animations are skipped when reduced
|
/// Respects [m3ReducedMotion] — the animation is skipped when reduced
|
||||||
/// motion is enabled.
|
/// motion is enabled, showing the badge immediately.
|
||||||
class M3BounceIcon extends StatefulWidget {
|
class M3BounceIcon extends StatefulWidget {
|
||||||
const M3BounceIcon({
|
const M3BounceIcon({
|
||||||
super.key,
|
super.key,
|
||||||
|
|
@ -814,36 +812,22 @@ class M3BounceIcon extends StatefulWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
class _M3BounceIconState extends State<M3BounceIcon>
|
class _M3BounceIconState extends State<M3BounceIcon>
|
||||||
with TickerProviderStateMixin {
|
with SingleTickerProviderStateMixin {
|
||||||
late final AnimationController _entranceCtrl;
|
late final AnimationController _entranceCtrl;
|
||||||
late final AnimationController _pulseCtrl;
|
|
||||||
late final Animation<double> _entrance;
|
late final Animation<double> _entrance;
|
||||||
late final Animation<double> _pulse;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
// One-shot spring entrance: scale 0 → 1.0 with natural overshoot.
|
||||||
// Entrance: scale 0 → 1.0 with spring overshoot.
|
|
||||||
_entranceCtrl = AnimationController(vsync: this, duration: M3Motion.long);
|
_entranceCtrl = AnimationController(vsync: this, duration: M3Motion.long);
|
||||||
_entrance = CurvedAnimation(parent: _entranceCtrl, curve: M3Motion.spring);
|
_entrance = CurvedAnimation(parent: _entranceCtrl, curve: M3Motion.spring);
|
||||||
|
|
||||||
// Idle pulse: 1.0 → 1.06 → 1.0, repeating every 2.5 s.
|
|
||||||
_pulseCtrl = AnimationController(
|
|
||||||
vsync: this,
|
|
||||||
duration: const Duration(milliseconds: 2500),
|
|
||||||
)..repeat(reverse: true);
|
|
||||||
_pulse = Tween<double>(begin: 1.0, end: 1.06).animate(
|
|
||||||
CurvedAnimation(parent: _pulseCtrl, curve: Curves.easeInOut),
|
|
||||||
);
|
|
||||||
|
|
||||||
_entranceCtrl.forward();
|
_entranceCtrl.forward();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
_entranceCtrl.dispose();
|
_entranceCtrl.dispose();
|
||||||
_pulseCtrl.dispose();
|
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -861,15 +845,7 @@ class _M3BounceIconState extends State<M3BounceIcon>
|
||||||
|
|
||||||
if (m3ReducedMotion(context)) return badge;
|
if (m3ReducedMotion(context)) return badge;
|
||||||
|
|
||||||
return ScaleTransition(
|
return ScaleTransition(scale: _entrance, child: badge);
|
||||||
scale: _entrance,
|
|
||||||
child: AnimatedBuilder(
|
|
||||||
animation: _pulse,
|
|
||||||
builder: (_, child) =>
|
|
||||||
Transform.scale(scale: _pulse.value, child: child),
|
|
||||||
child: badge,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user