observe method
Observes this controller's animated value as a reactive Bloom<double>.
Caution: VSYNC Coupling (Passive Observer)
observe is a passive observer of this controller's timeline and does NOT generate physical VSYNC ticks on its own.
For this Bloom node to emit updates, the controller must have an active VSYNC host
actively animating it in the widget tree (e.g., via composed.animate(...)).
System Architectural Flow
[composed.animate (Active VSYNC Socket)] ──> [DurableAnimationController (Timeline)]
│
▼
[controller.observe() (Passive Bloom<double>)] <──────────────┘
distinct: Whentrue(default), suppresses pulses if animated value does not change.equals: Custom equality function.graceful: Optional teardown deferral policy.
Requires:
- If
equalsis provided,distinctmust betrue.
Ensures:
- Emits updated double values whenever the controller's animation updates.
Warning (Anti-Pattern Prevention):
- Calling
controller.observe()without mounting the controller in an active VSYNC socket (such ascomposed.animate) will produce a dormant Bloom that never ticks.
BAD:
// [Anti-Pattern] Expecting observe() to tick without a mounted VSYNC host
final ctrl = DurableAnimationController(duration: const Duration(seconds: 1))..forward();
final animatedBloom = ctrl.observe(); // Never receives ticks because no vsync is mounted!
GOOD:
// [Recommended] Mount controller via composed.animate, observe timeline reactively elsewhere
final ctrl = DurableAnimationController(duration: const Duration(seconds: 1));
final animatedBloom = ctrl.observe();
Widget build(BuildContext context) {
return Column(
children: [
composed.animate(ctrl, (context, via, c) => FadeTransition(opacity: c.view, child: const Text('Host'))),
composed((context, via) => Text('Progress: ${via(animatedBloom).toStringAsFixed(2)}')),
],
);
}
Implementation
Bloom<double> observe({
bool distinct = true,
bool Function(double previous, double next)? equals,
Graceful? graceful,
}) =>
_view.toBloom(
distinct: distinct,
equals: equals,
graceful: graceful,
);