Skip to content

Bug: moveY and fadeIn only partially animate after a few state changes #154

@0xharkirat

Description

@0xharkirat

❓ What I’m trying to do

Screen.Recording.2025-04-16.at.10.12.35.am.mov

I'm building a toggle button that changes text (like "Light" ↔ "Dark") with a smooth moveY + fadeIn animation every time the text changes. I’m using:

  • .moveY(begin: 20, end: 0)
  • .fadeIn()
  • onPlay: (controller) => controller.forward(from: 0)
  • Unique ValueKey per animated widget (e.g. ValueKey('new-$_animId'))

💥 Problem

The first one or two taps animate correctly. After that:

  • Only fadeIn continues to work
  • The moveY animation stops completely — it either doesn't trigger or is skipped entirely
  • Even though I’m using unique keys and controller.forward(from: 0), the animation does not restart
Screen.Recording.2025-04-16.at.10.15.08.am.mov

✅ What I’ve tried

  • Replacing .slideY() with .moveY() → same issue
  • Forcing widget rebuild with incremented _animId
  • Logging the key + checking onPlay fires (it does)
  • Rebuilding in isolation (minimal widget outside of any app context)
  • Setting animate().moveY(...).fadeIn() on a fresh widget every time

🧪 Repro Code (Minimal, Copy-Paste Ready)

import 'package:flutter/material.dart';
import 'package:flutter_animate/flutter_animate.dart';

void main() {
  runApp(const MaterialApp(home: Scaffold(body: Center(child: ToggleTextDemo()))));
}

class ToggleTextDemo extends StatefulWidget {
  const ToggleTextDemo({super.key});

  @override
  State<ToggleTextDemo> createState() => _ToggleTextDemoState();
}

class _ToggleTextDemoState extends State<ToggleTextDemo> {
  String _text = 'Light';
  String? _prevText;
  int _animId = 0;

  void _toggle() {
    setState(() {
      _prevText = _text;
      _text = _text == 'Light' ? 'Dark' : 'Light';
      _animId++; // force rebuild and re-animation
    });
  }

  @override
  Widget build(BuildContext context) {
    const style = TextStyle(fontSize: 24, fontWeight: FontWeight.bold);
    return GestureDetector(
      onTap: _toggle,
      child: SizedBox(
        height: 40,
        child: ClipRect(
          child: Stack(
            alignment: Alignment.center,
            children: [
              if (_prevText != null)
                Text(_prevText!, key: ValueKey('old-$_animId'), style: style)
                    .animate(onPlay: (controller) => controller.forward(from: 0))
                    .moveY(begin: 0, end: -20, duration: 300.ms)
                    .fadeOut(duration: 300.ms),
              Text(_text, key: ValueKey('new-$_animId'), style: style)
                  .animate(onPlay: (controller) => controller.forward(from: 0))
                  .moveY(begin: 20, end: 0, duration: 300.ms)
                  .fadeIn(duration: 300.ms),
            ],
          ),
        ),
      ),
    );
  }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions