首页 文章详情

Flutter Loading动画系列中最复杂的一个效果

老孟Flutter | 627 2021-10-14 13:52 0 0 0
UniSMS (合一短信)


Loading动画系列

github地址:https://github.com/LaoMengFlutter/flutter-do

最复杂的效果

我个人认为最复杂的,也是花费时间最长的动画效果

放慢来看,是一个3x3的矩形,从左下角开始,每一斜排依次缩小,再还原的过程,下面就一步步实现,先绘制一个矩形:

class Square extends StatelessWidget {

  final Color color;

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

  @override
  Widget build(BuildContext context) {
    return Container(
      color: color,
    );
  }
}

绘制3x3的矩形,并给每一个矩形添加 「ScaleTransition」 ,用于后面实现缩放

@override
  Widget build(BuildContext context) {
    return SizedBox.fromSize(
      size: Size.square(widget.size),
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        mainAxisSize: MainAxisSize.max,
        children: <Widget>[
          Row(
            mainAxisSize: MainAxisSize.max,
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              _square(_anim3, 0),
              _square(_anim4, 1),
              _square(_anim5, 2),
            ],
          ),
          Row(
            mainAxisSize: MainAxisSize.max,
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              _square(_anim2, 3),
              _square(_anim3, 4),
              _square(_anim4, 5),
            ],
          ),
          Row(
            mainAxisSize: MainAxisSize.max,
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              _square(_anim1, 6),
              _square(_anim2, 7),
              _square(_anim3, 8),
            ],
          ),
        ],
      ),
    );
  }

  Widget _square(Animation<double> animation, int index) {
    return ScaleTransition(
      scale: animation,
      child: SizedBox.fromSize(
          size: Size.square(widget.size / 3.0),
          child: Square(
            color: widget.color,
          )),
    );
  }

重点来了,为什么需要5个 「Animation」 呢?因为共有5个斜排,同一个斜排使用一个Animation,如图:

其中1-5数字代表代码中的 _anim1, _anim2, _anim3, _anim4, _anim5,动画的效果都是依次缩小,再还原的过程,但1-2-3-4-5依次完成,并不是同时完成,代码如下:

_anim1 = TweenSequence([
      TweenSequenceItem(tween: Tween(begin: 1.0, end: 0.0), weight: 50),
      TweenSequenceItem(tween: Tween(begin: 0.0, end: 1.0), weight: 50),
    ]).animate(CurvedAnimation(
        parent: _controller, curve: Interval(0.10.6, curve: widget.curve)));

    _anim2 = TweenSequence([
      TweenSequenceItem(tween: Tween(begin: 1.0, end: 0.0), weight: 50),
      TweenSequenceItem(tween: Tween(begin: 0.0, end: 1.0), weight: 50),
    ]).animate(CurvedAnimation(
        parent: _controller, curve: Interval(0.20.7, curve: widget.curve)));

    _anim3 = TweenSequence([
      TweenSequenceItem(tween: Tween(begin: 1.0, end: 0.0), weight: 50),
      TweenSequenceItem(tween: Tween(begin: 0.0, end: 1.0), weight: 50),
    ]).animate(CurvedAnimation(
        parent: _controller, curve: Interval(0.30.8, curve: widget.curve)));

    _anim4 = TweenSequence([
      TweenSequenceItem(tween: Tween(begin: 1.0, end: 0.0), weight: 50),
      TweenSequenceItem(tween: Tween(begin: 0.0, end: 1.0), weight: 50),
    ]).animate(CurvedAnimation(
        parent: _controller, curve: Interval(0.40.9, curve: widget.curve)));

    _anim5 = TweenSequence([
      TweenSequenceItem(tween: Tween(begin: 1.0, end: 0.0), weight: 50),
      TweenSequenceItem(tween: Tween(begin: 0.0, end: 1.0), weight: 50),
    ]).animate(CurvedAnimation(
        parent: _controller, curve: Interval(0.51.0, curve: widget.curve)));

难点解决了,下面是完整的代码:

import 'package:flutter/material.dart';

///
/// desc:

///

class SquareGridScaleLoading extends StatefulWidget {

  final double size;
  final Duration duration;
  final Curve curve;
  final Color color;

  const SquareGridScaleLoading(
      {Key? key,
      this.color = Colors.white,
      this.size = 48.0,
      this.duration = const Duration(milliseconds: 1500),
      this.curve = Curves.linear})
      : super(key: key);

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

class _SquareGridScaleLoadingState extends State<SquareGridScaleLoading>
    with SingleTickerProviderStateMixin 
{
  late AnimationController _controller;
  late Animation<double> _anim1, _anim2, _anim3, _anim4, _anim5;

  @override
  void initState() {
    _controller = AnimationController(vsync: this, duration: widget.duration)
      ..repeat();

    _anim1 = TweenSequence([
      TweenSequenceItem(tween: Tween(begin: 1.0, end: 0.0), weight: 50),
      TweenSequenceItem(tween: Tween(begin: 0.0, end: 1.0), weight: 50),
    ]).animate(CurvedAnimation(
        parent: _controller, curve: Interval(0.10.6, curve: widget.curve)));

    _anim2 = TweenSequence([
      TweenSequenceItem(tween: Tween(begin: 1.0, end: 0.0), weight: 50),
      TweenSequenceItem(tween: Tween(begin: 0.0, end: 1.0), weight: 50),
    ]).animate(CurvedAnimation(
        parent: _controller, curve: Interval(0.20.7, curve: widget.curve)));

    _anim3 = TweenSequence([
      TweenSequenceItem(tween: Tween(begin: 1.0, end: 0.0), weight: 50),
      TweenSequenceItem(tween: Tween(begin: 0.0, end: 1.0), weight: 50),
    ]).animate(CurvedAnimation(
        parent: _controller, curve: Interval(0.30.8, curve: widget.curve)));

    _anim4 = TweenSequence([
      TweenSequenceItem(tween: Tween(begin: 1.0, end: 0.0), weight: 50),
      TweenSequenceItem(tween: Tween(begin: 0.0, end: 1.0), weight: 50),
    ]).animate(CurvedAnimation(
        parent: _controller, curve: Interval(0.40.9, curve: widget.curve)));

    _anim5 = TweenSequence([
      TweenSequenceItem(tween: Tween(begin: 1.0, end: 0.0), weight: 50),
      TweenSequenceItem(tween: Tween(begin: 0.0, end: 1.0), weight: 50),
    ]).animate(CurvedAnimation(
        parent: _controller, curve: Interval(0.51.0, curve: widget.curve)));

    super.initState();
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return SizedBox.fromSize(
      size: Size.square(widget.size),
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        mainAxisSize: MainAxisSize.max,
        children: <Widget>[
          Row(
            mainAxisSize: MainAxisSize.max,
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              _square(_anim3, 0),
              _square(_anim4, 1),
              _square(_anim5, 2),
            ],
          ),
          Row(
            mainAxisSize: MainAxisSize.max,
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              _square(_anim2, 3),
              _square(_anim3, 4),
              _square(_anim4, 5),
            ],
          ),
          Row(
            mainAxisSize: MainAxisSize.max,
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              _square(_anim1, 6),
              _square(_anim2, 7),
              _square(_anim3, 8),
            ],
          ),
        ],
      ),
    );
  }

  Widget _square(Animation<double> animation, int index) {
    return ScaleTransition(
      scale: animation,
      child: SizedBox.fromSize(
          size: Size.square(widget.size / 3.0),
          child: Square(
            color: widget.color,
          )),
    );
  }
}

class Square extends StatelessWidget {

  final Color color;

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

  @override
  Widget build(BuildContext context) {
    return Container(
      color: color,
    );
  }
}

最终的效果如下:



你可能还喜欢

关注「老孟Flutter」
让你每天进步一点点


good-icon 0
favorite-icon 0
收藏
回复数量: 0
    暂无评论~~
    Ctrl+Enter