flutteranimation

How to make a smooth animation when widgets change?


I want to make a smooth animation for my widgets: small floating icon button and big blue square. Here is my prototype code.

class MyApp extends StatelessWidget {
  const MyApp({super.key});
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      builder: (context, child) {
        return Scaffold(body: Stack(children: [AnimatedWidget()]));
      },
    );
  }
}

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

  @override
  AnimatedWidgetState createState() => AnimatedWidgetState();
}

class AnimatedWidgetState extends State<AnimatedWidget> {
  bool _isOpen = false;

  void toggleButton() {
    setState(() {
      _isOpen = !_isOpen;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Positioned(
      bottom: 20,
      right: 20,
      child: AnimatedSwitcher(
        duration: Duration(milliseconds: 200),
        transitionBuilder: (child, animation) {
          return FadeTransition(
            opacity: animation.drive(Tween(begin: 0.0, end: 1.0)),
            child: ScaleTransition(scale: animation, child: child),
          );
        },
        child:
            _isOpen
                ? Column(
                  key: ValueKey('square'),
                  crossAxisAlignment: CrossAxisAlignment.end,
                  children: [
                    GestureDetector(onTap: toggleButton, child: Row(children: [Text('Close'), Icon(Icons.close)])),
                    Container(
                      width: 300,
                      height: 300,
                      decoration: BoxDecoration(color: Colors.blue, shape: BoxShape.rectangle),
                      child: Center(child: Text('This is square')),
                    ),
                  ],
                )
                : FloatingActionButton(key: ValueKey('add'), onPressed: toggleButton, child: Icon(Icons.add)),
      ),
    );
  }
}

There is a flaw in my example. When I click the small button and the animation plays, I can see how the small widget is in the middle of the large widget. But I would like the animation to be smooth and the widgets to transform smoothly. How can I fix this? I will be glad any help.


Solution

  • Try to set layoutBuilder to AnimatedSwitcher like this.

    child: AnimatedSwitcher(
      // ...
    
      layoutBuilder: (currentChild, previousChildren) {
        return Stack(
          alignment: Alignment.bottomRight,
          children: <Widget>[...previousChildren, if (currentChild != null) currentChild],
        );
      },
    
      // ...
    ),
    

    It's same with defaultLayoutBuilder but only Stack's alignment changed.