Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 47 additions & 20 deletions lib/src/widgets/animated_mesh_gradient/animated_mesh_gradient.dart
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ class _AnimatedMeshGradientState extends State<AnimatedMeshGradient> {

Ticker? _ticker;

/// Stored so we can remove it in [dispose]. Avoids stale listener after
/// widget is disposed (e.g. when list item is replaced by overlay placeholder).
VoidCallback? _controllerListener;

/// The current time value used to control the animation phase.
late double _delta = widget.seed ?? 0;

Expand Down Expand Up @@ -101,36 +105,59 @@ class _AnimatedMeshGradientState extends State<AnimatedMeshGradient> {
}

WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
// Define the ticker because we are certain it will be used next
_ticker = Ticker(_tickerCallback);
if (!mounted) return;
_initTicker();
});
}

// Start the animation to account for isAnimating already being true at init
if (widget.controller == null || widget.controller!.isAnimating.value) {
_ticker!.start();
}
void _initTicker() {
final VoidCallback? oldListener = _controllerListener;
final AnimatedMeshGradientController? c = widget.controller;
if (oldListener != null && c != null) {
c.isAnimating.removeListener(oldListener);
_controllerListener = null;
}

// Make sure there is no listener added when controller is null
if (widget.controller == null) {
return;
}
_ticker?.dispose();
_ticker = Ticker(_tickerCallback);

// Register a listener callback for controller.isAnimating changes
widget.controller!.isAnimating.addListener(() {
if (widget.controller!.isAnimating.value && !_ticker!.isActive) {
_ticker!.start();
return;
}
// Start the animation to account for isAnimating already being true at init
if (c == null || c.isAnimating.value) {
_ticker!.start();
}

if (c == null) return;

if (!widget.controller!.isAnimating.value && _ticker!.isActive) {
_ticker!.stop();
void onControllerChange() {
if (!mounted) return;
final Ticker? t = _ticker;
if (t == null) return;
if (widget.controller!.isAnimating.value) {
if (!t.isActive) {
// Flutter's Ticker cannot be restarted after stop(); create a new one.
_initTicker();
}
});
});
return;
}
if (t.isActive) {
t.stop();
}
}

_controllerListener = onControllerChange;
c.isAnimating.addListener(_controllerListener!);
}

@override
void dispose() {
final VoidCallback? listener = _controllerListener;
final AnimatedMeshGradientController? c = widget.controller;
if (listener != null && c != null) {
c.isAnimating.removeListener(listener);
_controllerListener = null;
}
_ticker?.dispose();
_ticker = null;
super.dispose();
}

Expand Down