Flutter Advanced - Animación detallada

Tabla de contenido

categoría de animación

1. Animación implícita (automática)

2. Animación explícita (control manual)

3. Otras animaciones (CustomPainter)

categoría de animación

Hay varios tipos de animaciones en Flutter:

  • Animaciones implícitas: animaciones predefinidas que se activan automáticamente al cambiar las propiedades del widget, como  AnimatedContainer, AnimatedOpacity , AnimatedPaddingetc.
  • Animaciones explícitas:   controle manualmente las animaciones usando Animation y  clases.AnimationController
  • Animación física: animación basada en leyes físicas, como  SpringSimulation, FrictionSimulation etc.

1. Animación implícita (automática)

 AnimatedSwitcher(
          duration: const Duration(seconds: 2),
          transitionBuilder: (child, animation) {
            return FadeTransition(
              opacity: animation,
              child: ScaleTransition(
                scale: animation,
                child: child,
              ),
            );
          },
          child: const Text("Hello"),
        )

Interpolación de movimiento (se han determinado el primer cuadro (0.0) y el último cuadro (1.0), si FPS 60 complementa los 58 cuadros del medio)

 TweenAnimationBuilder(
            tween: Tween(begin: 0.0, end: 1.0),
            duration: const Duration(seconds: 5),
            builder: (BuildContext context, Object? value, Widget? child) {
              return Opacity(
                opacity: value as double,
                child: Container(
                  width: 300,
                  height: 300,
                  color: Colors.red[200],
                ),
              );
            }))
TweenAnimationBuilder(
            tween: Tween(begin: 20.0, end: 50.0),
            duration: const Duration(seconds: 5),
            builder: (context,double value, Widget? child) {
              return Container(
                  width: 300,
                  height: 300,
                  color: Colors.red[200],
                  child: Text('Hello', style: TextStyle(fontSize: value)));
            }))

2. Animación explícita (control manual)

class _MyHomePageState extends State<MyHomePage>
    with SingleTickerProviderStateMixin {
  late AnimationController _controller;

  @override
  void initState() {
    _controller =
        AnimationController(vsync: this, duration: const Duration(seconds: 4))..repeat();
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(),
        body: AnimatedBuilder(
            animation: _controller,
            builder: (BuildContext context, Widget? child) {
              return Opacity(
                  opacity: _controller.value,
                  child: Container(
                    width: 300,
                    height: 300,
                    color: Colors.blue,
                  ));
            }));
  }
}

Si la animación de degradado anterior no usa el control universal de animación de pantalla clásica AnimatedBuilder, puede usar FadeTransition directamente

 FadeTransition(
                    opacity: _controller,
                    child:
                        Container(width: 200, height: 200, color: Colors.blue),
                  )),

Una animación que gira sin fin

class _MyHomePageState extends State<MyHomePage>
    with SingleTickerProviderStateMixin {
      
  late AnimationController _controller;
  bool _loading = false;

  @override
  void initState() {
    _controller =
        AnimationController(vsync: this, duration: const Duration(seconds: 1));
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(),
        body: Center(
          child: RotationTransition(
              turns: _controller, child: const Icon(Icons.refresh, size: 100)),
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: () {
            if (_loading) {
              _controller.reset();
            } else {
              _controller.repeat();
            }
            _loading = !_loading;
          },
        ));
  }
}

FadeTransition、ScaleTransition、SlideTransition

El controlador conecta Tween y Curve en serie

ScaleTransition(
             scale: _controller.drive(Tween(begin: 0.5, end:2.0)), child: const Icon(Icons.refresh, size: 100)),
        ),
SlideTransition(
             position: _controller.drive(Tween(begin: Offset(0,0), end:Offset(1,0))), 
// position:Tween(begin: const Offset(0, 0), end: const Offset(1, 0)).animate(_controller),
child: const Icon(Icons.refresh, size: 100)),

 position:Tween(begin: const Offset(0, 0), end: const Offset(1, 0))
                      .chain(CurveTween(curve: Curves.elasticInOut))
                      .animate(_controller),
class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage>
    with SingleTickerProviderStateMixin {

  late AnimationController _controller;
  final bool _loading = false;

  @override
  void initState() {
    _controller =
        AnimationController(vsync: this, duration: const Duration(seconds: 4))..repeat(reverse:true);
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: Center(
          child: Column(children: [
       SlidingBox(
          controller: _controller,
          color: Colors.blue[100]!,
          interval: const Interval(0.0, 0.2),
        ),
          SlidingBox(
          controller: _controller,
          color: Colors.blue[300]!,
          interval: const Interval(0.2, 0.4),
        ),
          SlidingBox(
          controller: _controller,
          color: Colors.blue[500]!,
          interval: const Interval(0.4, 0.6),
        ),
          SlidingBox(
          controller: _controller,
          color: Colors.blue[700]!,
          interval: const Interval(0.6, 0.8),
        ),
        SlidingBox(
          controller: _controller,
          color: Colors.blue[900]!,
          interval: const Interval(0.8, 1.0),
        ),
      ])),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          _controller.forward();
        },
      ),
    );
  }
}

class SlidingBox extends StatelessWidget {
  final AnimationController controller;
  final Color color;
  final Interval interval;

  const SlidingBox(
      {Key? key,
      required this.controller,
      required this.color,
      required this.interval})
      : super(key: key);

  @override
  Widget build(BuildContext context) {
    return SlideTransition(
        position: Tween(begin: Offset.zero, end: const Offset(0.2, 0))
            .chain(CurveTween(curve: Curves.bounceOut))
            .chain(CurveTween(curve: interval))
            .animate(controller),
        //CurveTween(curve: const Interval(0.8, 1.0)) 控制动画从最后的1/5时间开始到结束
        child: Container(width: 300, height: 100, color: color));
  }
}

Animación de luz de respiración personalizada 

 

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> with TickerProviderStateMixin {
  late AnimationController _expansionController;
  late AnimationController _opacityController;

  @override
  void initState() {
    _expansionController = AnimationController(vsync: this);
    _opacityController = AnimationController(vsync: this);
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(),
        body: Center(
          child: FadeTransition(
            opacity: Tween(begin: 1.0, end: 0.5).animate(_opacityController),
            child: AnimatedBuilder(
                animation: _expansionController,
                builder: (BuildContext context, Widget? child) {
                  return Container(
                    height: 200,
                    width: 200,
                    decoration: BoxDecoration(
                      shape: BoxShape.circle,
                      color: Colors.blue,
                      gradient: RadialGradient(colors: [
                        Colors.blue[600]!,
                        Colors.blue[100]!,
                      ], stops: [
                        _expansionController.value,
                        _expansionController.value + 0.1
                      ]),
                    ),
                  );
                }),
          ),
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: () async {
            _expansionController.duration = const Duration(seconds: 4);
            _expansionController.forward();
            await Future.delayed(const Duration(seconds: 4));
            _opacityController.duration = const Duration(milliseconds: 1750);
            _opacityController.repeat(reverse: true);
            await Future.delayed(const Duration(seconds: 7));
            _opacityController.reset();
            _expansionController.duration = const Duration(seconds: 8);
            _expansionController.reverse();
          },
        ));
  }
}

3. Otras animaciones (CustomPainter)

manipulación directa del subyacente

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage>
    with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  final List<Snowflake> _snowflakes =
      List.generate(100, (index) => Snowflake());

  @override
  void initState() {;
    _controller =
        AnimationController(vsync: this, duration: const Duration(seconds: 4))
          ..repeat();
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(),
        body: Center(
          child: Container(
            width: double.infinity,
            height: double.infinity,
            decoration: const BoxDecoration(
              gradient: LinearGradient(
                  begin: Alignment.topCenter,
                  end: Alignment.bottomCenter,
                  colors: [Colors.blue, Colors.lightBlue, Colors.white],
                  stops: [0.0, 0.75, 0.95]),
            ),
            child: AnimatedBuilder(
              animation: _controller,
              builder: (BuildContext context, Widget? child) {
                for (var snow in _snowflakes) {
                  snow.fall();
                }
                return CustomPaint(
                  painter: MyPainter(_snowflakes),
                );
              },
            ),
          ),
        ));
  }
}

class MyPainter extends CustomPainter {
  final List<Snowflake> _snowflakes;
  MyPainter(this._snowflakes);

  @override
  void paint(Canvas canvas, Size size) {
    final whitePaint = Paint()..color = Colors.white;
    canvas.drawCircle(size.center(const Offset(0, 100)), 60.0, whitePaint);
    canvas.drawOval(
        Rect.fromCenter(
            center: size.center(const Offset(0, 260)), width: 230, height: 250),
        whitePaint);
    _snowflakes.forEach((snowflake) {
      canvas.drawCircle(
          Offset(snowflake.x, snowflake.y), snowflake.radius, whitePaint);
    });
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) => true;
}

class Snowflake {
  double x = Random().nextDouble() * 400;
  double y = Random().nextDouble() * 800;
  double radius = Random().nextDouble() * 2 + 2;
  double velocity = Random().nextDouble() * 4 + 2;
  void fall() {
    y += velocity;
    if (y > 800) {
      y = 0;
      x = Random().nextDouble() * 400;
      radius = Random().nextDouble() * 2 + 2;
      velocity = Random().nextDouble() * 4 + 2;
    }
  }
}

Supongo que te gusta

Origin blog.csdn.net/RreamigOfGirls/article/details/131377796
Recomendado
Clasificación