Search code examples
flutterflutter-layoutflutter-animation

Flutter IconButton does not play animation if used for navigation, showing popup etc


I am using IconButtons in my application for opening popups, deleting ListTiles from ListViews, navigating to other views etc.

To my surprise the onPressed callback always gets triggered before the animation starts to play resulting in that the animation will not play at all. This is confusing to the user because there is no feedback that he pushed the button.

The setup looks something like this.

This is the code for the add button in the top right corner:

IconButton(
    onPressed: () {
      showDialog(
          context: context,
          builder: (context) {
            return AddDevicePopup(
              ...
            ).build(context);
          });
    },
    icon: const Icon(
      Icons.add_circle_outline_rounded,
      size: 30.0,
    )
)

When the user taps the button the popup immediately appears but the animation won't get played.

This is the same for the IconButtons on the tiles:

  • the edit button opens a popup immediately and the ripple or splash animation won't play.
  • the delete button removes the element from the list. In this case the ListTile element gets removed and so the IconButton disappears without the animation getting played.

In every case there is a Material widget that is an ancestor of the IconButton so wrapping it in a Material widget does not solve the problem. I have double checked it by removing the showDialog part from the callback, in these cases all of the IconButtons play the splash / ripple animation as expected.

How do I make the onPressed to wait for the animation to at least be started. I did not find any solution. Is is possible to trigger this animation via code? In that case I can add that to the beginning of the onPressed callback.


Solution

  • To add animations, you must use showGeneralDialog instead of showDialog.

    The implementation looks like this:

    showGeneralDialog(
        barrierDismissible: true,
        barrierColor: Colors.black.withOpacity(0.5),
        transitionDuration: const Duration(milliseconds: 200),
        context: context,
        pageBuilder: (_, __, ___) {
          return AddDevicePopup(
              ...
            ).build(context);
        },
        //Customize your animation here
        transitionBuilder: (_, a1, __, child) {
          return Transform.scale(
            scale: a1.value,
            child: Opacity(
              opacity: a1.value,
              child: child,
            ),
          );
        },
      );