Sencilla animación bounce con AnimatedContainer en flutter

Dentro del mundo de las animaciones, bounce consiste en el movimiento repetido  de arriba hacia abajo de un elemento simulando el efecto de rebote  de una pelota. Una animación muy sencilla y popular, a continuación veremos como crearla en flutter.

Como todo en todo, existen miles de maneras de hacer una cosa y para este ejemplo haremos uso del widget AnimatedContainer, que como su nombre lo indica, es la versión animada de su hermano Container, que automáticamente anima el cambio entre los valores previos y los nuevos. 

Tomando como base un código ya trabajado el resultado que se obtiene al final, es algo similar a esto..

A Comencemos con la estructura del código; Es necesario que nuestro AnimatedContainer lo coloquemos en otro widget que nos sirva como contenedor para darle espacio y "sostén" logrando que solo se mueva arriba y abajo, que no se extienda y mueva el resto de elementos...


Container(
      padding: EdgeInsets.all(3),
      alignment: Alignment(0, 0),
      width: double.infinity,
      height: 110,
      color: Colors.transparent,
      
      child: //Aqui va nuestro Animated container
}

Pero el protagonista de nuestro post, AnimatedContainer es el encargado de administrar la magia... 


AnimatedContainer(
        duration: Duration(milliseconds: 500),
        curve: Curves.bounceOut,
        height: _height, //*** alto dinámico 
        decoration: BoxDecoration(
          boxShadow:[ BoxShadow( 
            color: const Color.fromARGB(127, 6, 44, 78), // Color de la sombra con opacidad 
            spreadRadius: _sizeShadow, //*** Expansión de la sombra dinámico 
            blurRadius: _sizeShadow, //*** Suavidad de la sombra dinámica 
            offset: Offset(-1, 1), // Dirección de la sombra (X, Y) 
            ), ],
          borderRadius: BorderRadius.all( Radius.circular(8)),
          border: Border.all(color: getColorText()!.withAlpha(100)),
          color: const Color.fromRGBO(251, 193, 11, 1)
        ),
        child: //Aca se agrega todo el contenido del elemento
)


Dentro del código de nuestro elemento central, como lo dijimos anteriormente es un container cualquiera (mismas propiedades ) pero se comporta de manera animada ante algún cambio; En nuestro caso la propiedad height (alto del elemento), spreadRadius( tamaño de la sombra ) y blurRadius( suavidad de la sombra). Me parece necesario (y con el temor de verme necio) hacer hincapié  en que para ver algún tipo de efecto es necesario aplicar un cambio en alguna de sus propiedades, para ello será  necesario hacer uso de los estados del widget.

Supongamos que tenemos un widget state ful y dentro tenemos nuestras propiedades dinámicas y manejo del estado... 


class PaymentCard extends StatefulWidget {

  PaymentCard({
    super.key, 
    
    });

  @override
  State createState() => _PaymentCardState();
}

class _PaymentCardState extends State {
  //se inicializan las variables de las proas dinámicas
  double _height = 96;
  double _sizeShadow = 0;
  
  //Esta función se manda llamar al hacer tap ene el botón
  void _startBounceAnimation() {
    setState(() {
      _height = 123.0; 
      _sizeShadow = 5;
    });

    Future.delayed(Duration(milliseconds: 150), () {
      setState(() {
        _height = 96.0; // Reset the height after the bounce animation
        _sizeShadow = 0;
      });
    });
  }

}

El código es sencillo...
En un principio se inicializaran las variables que dan el valor inicial de nuestro container.

class _PaymentCardState extends State {
  //se inicializan las variables de las proas dinámicas
  double _height = 96;
  double _sizeShadow = 0;

Y la función que cambiará el estado y lo regresará a su estado inicial con un delay

void _startBounceAnimation() {
    setState(() {
      height = 123.0; 
      sizeShadow = 5;
    });

    Future.delayed(Duration(milliseconds: 150), () {
      setState(() {
        height = 96.0; // Reset the height after the bounce animation
        sizeShadow = 0;
      });
    });
  }

Desde el evento del botón...

TextButton(
  style: ButtonStyle(
    splashFactory: NoSplash.splashFactory //para quitar la animación del botón y no sobrecargar visualmente
  ),
  onPressed: () {
     _startBounceAnimation();
   }, 
   child: //contenido del botón
)


Nota: este no es código completo del resultado de la imagen, es solo la parte medular de la animación.
Quizá no sea propiamente una animación bounce, pero nos sirve un poco para darle un vistazo al widget AnimatedContainer.