Flutter – Simulación de Física en Animación

La simulación física en Flutter es una manera hermosa de animar los componentes de la aplicación flutter para que se vea más realista e interactivo. Estos se pueden usar para crear una variedad de animaciones, como objetos que caen debido a la gravedad, o hacer que un contenedor parezca estar unido a un resorte. En este artículo, exploraremos lo mismo mediante la creación de una aplicación simple.

Siga los pasos a continuación para crear una simulación física simple en un widget:

  • Desarrollar un controlador de animación.
  • Usa gestos para el movimiento.
  • Muestre la animación.
  • Utilice la velocidad para simular el movimiento de salto.

Vamos a discutirlos en detalle:

Desarrollo de un controlador de animación:

Para crear el controlador de animación, cree un StatefulWidget llamado DraggableCard como se muestra a continuación:

Dart

import 'package:flutter/material.dart';
 
main() {
  runApp(MaterialApp(home: PhysicsCardDragDemo()));
}
 
class PhysicsCardDragDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: DraggableCard(
        child: FlutterLogo(
          size: 128,
        ),
      ),
    );
  }
}
 
class DraggableCard extends StatefulWidget {
  final Widget child;
  DraggableCard({this.child});
 
  @override
  _DraggableCardState createState() => _DraggableCardState();
}
 
class _DraggableCardState extends State<DraggableCard> {
  @override
  void initState() {
    super.initState();
  }
 
  @override
  void dispose() {
    super.dispose();
  }
 
  @override
  Widget build(BuildContext context) {
    return Align(
      child: Card(
        child: widget.child,
      ),
    );
  }
}

Uso de gestos para el movimiento:

Aquí haremos que el widget se mueva cuando se arrastre en cualquier dirección. El movimiento se puede mapear usando un GestureDetector que maneja onPanEnd , onPanUpdate y onPanDown como se muestra a continuación:

Dart

@override
Widget build(BuildContext context) {
  var size = MediaQuery.of(context).size;
  return GestureDetector(
    onPanDown: (details) {},
    onPanUpdate: (details) {
      setState(() {
        _dragAlignment += Alignment(
          details.delta.dx / (size.width / 2),
          details.delta.dy / (size.height / 2),
        );
      });
    },
    onPanEnd: (details) {},
    child: Align(
      alignment: _dragAlignment,
      child: Card(
        child: widget.child,
      ),
    ),
  );
}

Mostrar animación:

Use el campo Animation<Alignment> y el método _runAnimation para producir un efecto similar a un resorte como se muestra a continuación para mostrar la Animación:

Dart

Animation<Alignment> _animation;
 
void _runAnimation() {
  _animation = _controller.drive(
    AlignmentTween(
      begin: _dragAlignment,
      end: Alignment.center,
    ),
  );
 _controller.reset();
 _controller.forward();
}

Ahora, siempre que el controlador de animación produzca un valor, actualice el campo _dragAlignment como se muestra a continuación:

Dart

@override
void initState() {
  super.initState();
  _controller = AnimationController(vsync: this, duration: Duration(seconds: 1));
  _controller.addListener(() {
    setState(() {
      _dragAlignment = _animation.value;
    });
  });
}

Ahora, use el campo _dragAlignment para alinear el widget como se muestra a continuación:

Dart

child: Align(
  alignment: _dragAlignment,
  child: Card(
    child: widget.child,
  ),
),

Finalmente administre la Animación usando GestureDetector de la siguiente manera:

Dart

onPanDown: (details) {
 _controller.stop();
},
onPanUpdate: (details) {
 setState(() {
   _dragAlignment += Alignment(
     details.delta.dx / (size.width / 2),
     details.delta.dy / (size.height / 2),
   );
 });
},
onPanEnd: (details) {
 _runAnimation();
},

Usando la velocidad para simular el movimiento de salto:

Primero, importe el paquete Physics como se muestra a continuación:

import 'package:flutter/physics.dart';

Ahora use el método animateWith() de AnimationController para crear un efecto similar a un resorte como se muestra a continuación:

Dart

void _runAnimation(Offset pixelsPerSecond, Size size) {
  _animation = _controller.drive(
    AlignmentTween(
      begin: _dragAlignment,
      end: Alignment.center,
    ),
  );
 
  final unitsPerSecondX = pixelsPerSecond.dx / size.width;
  final unitsPerSecondY = pixelsPerSecond.dy / size.height;
  final unitsPerSecond = Offset(unitsPerSecondX, unitsPerSecondY);
  final unitVelocity = unitsPerSecond.distance;
 
  const spring = SpringDescription(
    mass: 30,
    stiffness: 1,
    damping: 1,
  );
 
  final simulation = SpringSimulation(spring, 0, 1, -unitVelocity);
 
  _controller.animateWith(simulation);
}

Finalmente, haga una llamada al método _runAnimation() con velocidad y tamaño como parámetro, como se muestra a continuación:

Dart

onPanEnd: (details) {
  _runAnimation(details.velocity.pixelsPerSecond, size);
},

Código fuente completo:

Dart

import 'package:flutter/material.dart';
import 'package:flutter/physics.dart';
 
main() {
  runApp(MaterialApp(home: PhysicsCardDragDemo()));
}
 
class PhysicsCardDragDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('GeeksForGeeks'),
        backgroundColor: Colors.green,
      ),
      body: DraggableCard(
        child: Container(
          width: 140,
          height: 140,
          decoration: BoxDecoration(
            color: Colors.green
          ),
        )
      ),
    );
  }
}
 
class DraggableCard extends StatefulWidget {
  final Widget child;
  DraggableCard({this.child});
 
  @override
  _DraggableCardState createState() => _DraggableCardState();
}
 
class _DraggableCardState extends State<DraggableCard>
    with SingleTickerProviderStateMixin {
  AnimationController _controller;
 
 
  Alignment _dragAlignment = Alignment.center;
 
  Animation<Alignment> _animation;
 
  void _runAnimation(Offset pixelsPerSecond, Size size) {
    _animation = _controller.drive(
      AlignmentTween(
        begin: _dragAlignment,
        end: Alignment.center,
      ),
    );
    // evaluating velocity
    final unitsPerSecondX = pixelsPerSecond.dx / size.width;
    final unitsPerSecondY = pixelsPerSecond.dy / size.height;
    final unitsPerSecond = Offset(unitsPerSecondX, unitsPerSecondY);
    final unitVelocity = unitsPerSecond.distance;
 
    const spring = SpringDescription(
      mass: 30,
      stiffness: 1,
      damping: 1,
    );
 
    final simulation = SpringSimulation(spring, 0, 1, -unitVelocity);
 
    _controller.animateWith(simulation);
  }
 
  @override
  void initState() {
    super.initState();
    _controller = AnimationController(vsync: this);
 
    _controller.addListener(() {
      setState(() {
        _dragAlignment = _animation.value;
      });
    });
  }
 
  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }
 
  @override
  Widget build(BuildContext context) {
    final size = MediaQuery.of(context).size;
    return GestureDetector(
      onPanDown: (details) {
        _controller.stop();
      },
      onPanUpdate: (details) {
        setState(() {
          _dragAlignment += Alignment(
            details.delta.dx / (size.width / 2),
            details.delta.dy / (size.height / 2),
          );
        });
      },
      onPanEnd: (details) {
        _runAnimation(details.velocity.pixelsPerSecond, size);
      },
      child: Align(
        alignment: _dragAlignment,
        child: Card(
          child: widget.child,
        ),
      ),
    );
  }
}

Producción:

Publicación traducida automáticamente

Artículo escrito por ddeevviissaavviittaa y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *