• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

Flutter 动画

武飞扬头像
xiangxiongfly915
帮助5

Flutter 动画

概述

Flutter对动画系统进行抽象、封装,使我们可以方便的进行动画开发。

  • AnimationController继承自Animation,负责动画的播放、停止等操作,通常在initState方法中初始化,在dispose方法中释放。Animation是一个抽象类,不能直接实例化。
  • Tween继承自Animatable,定义动画执行的范围,通常需要和AnimationController使用。
  • Curve类似于Android中的Interpolator,控制动画的速率。

简单使用

AnimationController类:

vsync:vsync可以防止屏幕外动画消耗不必要的资源,单个AnimationController使用SingleTickerProviderStateMixin,多个AnimationController使用TickerProviderStateMixin。

duration:动画执行时长。

lowerBound & upperBound:设置开始值和结束值。AnimationController的默认值是[0,1]。

addListener:动画监听。

addStatusListener:动画执行状态:
    - dismissed:动画停止在开始处。
    - forward:动画正在从开始处运行到结束处(正向运行)。
    - reverse:动画正在从结束处运行到开始处(反向运行)。
    - completed:动画停止在结束处。

动画控制方法:
    - forward():正向动画。
    - reverse():反向动画。
    - repeat():反复执行动画。
    - reset():重置动画。
学新通

缩放动画

学新通

late AnimationController _scaleController;
double _size = 100;

@override
void initState() {
    super.initState();
    _scaleController =
        AnimationController(vsync: this, duration: const Duration(seconds: 2), lowerBound: 100, upperBound: 200)
        ..addListener(() {
            setState(() {
                _size = _scaleController.value;
            });
        });
}

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

Container(
    width: _size,
    height: _size / 2,
    color: Colors.red.withOpacity(_opacity),
    transformAlignment: Alignment.center,
)
学新通

透明度动画

学新通

double _opacity = 1;
late AnimationController _alphaController;

@override
void initState() {
    super.initState();
    _alphaController = AnimationController(vsync: this, duration: const Duration(seconds: 2))
        ..addListener(() {
            setState(() {
                _opacity = _alphaController.value;
            });
        });
}

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

Container(
    width: _size,
    height: _size / 2,
    color: Colors.red.withOpacity(_opacity),
    transformAlignment: Alignment.center,
)
学新通

旋转动画

学新通

double _rotation = 1;
late AnimationController _rotationController;

@override
void initState() {
    super.initState();
    _rotationController =
        AnimationController(vsync: this, duration: const Duration(seconds: 2), lowerBound: 1, upperBound: 2)
        ..addListener(() {
            setState(() {
                _rotation = _rotationController.value;
            });
        });
}

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

Container(
    width: _size,
    height: _size / 2,
    color: Colors.red.withOpacity(_opacity),
    transformAlignment: Alignment.center,
    transform: Matrix4.rotationZ(pi / _rotation),
)
学新通

循环执行动画

学新通

_scaleController =
    AnimationController(vsync: this, duration: Duration(milliseconds: 500), lowerBound: 100, upperBound: 200)
    ..addStatusListener((status) {
        switch (status) {
            case AnimationStatus.dismissed:
                print("dismissed");
                _scaleController.forward();
                break;
            case AnimationStatus.forward:
                print("forward");
                break;
            case AnimationStatus.reverse:
                print("reverse");
                break;
            case AnimationStatus.completed:
                _scaleController.reverse();
                break;
        }
    })
    ..addListener(() {
        setState(() {
            _size = _controller.value;
        });
    });
学新通

Tween

负责两种状态之间的过渡转换。

使用

学新通

Color _color = Colors.green;
late AnimationController _controller;

@override
void initState() {
    super.initState();
    _controller = AnimationController(vsync: this, duration: const Duration(milliseconds: 3000))
        ..addListener(() {
            setState(() {
                _color = Color.lerp(Colors.green, Colors.blue, _controller.value)!;
            });
        });
}

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

GestureDetector(
    onTap: () {
        _controller.forward();
    },
    child: Container(
        width: 100,
        height: 100,
        color: _color,
        alignment: Alignment.center,
        child: const Text(
            "变色",
            style: TextStyle(color: Colors.white, fontSize: 18),
        ),
    ),
)
学新通

ColorTween

本质也是由 Color.lerp实现的。

final Color _startColor = Colors.yellow;
final Color _endColor = Colors.red;
late AnimationController _controller2;
late Animation<Color?> _animation;

@override
void initState() {
    super.initState();
    _controller2 = AnimationController(vsync: this, duration: const Duration(milliseconds: 3000))
        ..addListener(() {
            setState(() {});
        });
    _animation = ColorTween(begin: _startColor, end: _endColor).animate(_controller2);
}

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

GestureDetector(
    onTap: () {
        _controller2.forward();
    },
    child: Container(
        width: 100,
        height: 100,
        color: _animation.value,
        alignment: Alignment.center,
        child: const Text(
            "变色",
            style: TextStyle(color: Colors.white, fontSize: 18),
        ),
    ),
)
学新通

平移动画

学新通

late AnimationController _slideController;
late Animation<Offset> _animation;

@override
void initState() {
    super.initState();
    _slideController = AnimationController(vsync: this, duration: const Duration(seconds: 2))
        ..addListener(() {
            setState(() {});
        });
    _animation = Tween(begin: const Offset(0, 0), end: const Offset(100, 100)).animate(_slideController);
}

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

Transform.translate(
    offset: _animation.value,
    child: Container(
        width: _size,
        height: _size / 2,
        color: Colors.red.withOpacity(_opacity),
        transformAlignment: Alignment.center,
        transform: Matrix4.rotationZ(pi / _rotation),
    ),
)
学新通

Curve

Flutter中的Curve类似于Android中的Interpolator差值器,控制动画变化的速率,可分为:匀速、加速、减速等速率。

使用

学新通

_controller =
    AnimationController(vsync: this, duration: Duration(milliseconds: 1000))
    ..addListener(() {
        setState(() {});
    });
_animation = Tween(begin: 100.0, end: 200.0)
    .chain(CurveTween(curve: Curves.bounceInOut))
    .animate(_controller);
child: Container(
    width: _animation.value,
    height: _animation.value,
    color: Colors.red,
    alignment: Alignment.center,
    child: const Text(
        "变大",
        style: TextStyle(color: Colors.white, fontSize: 18),
    ),
)

自定义Curve

class _MyCurve extends Curve {
    late final int num;

    _MyCurve(this.num);

    @override
    double transformInternal(double t) {
        return t * num;
    }
}
_animation = Tween(begin: 100.0, end: 200.0)
    .chain(CurveTween(curve: _MyCurve(5)))
    .animate(_controller);

动画混合使用

多动画同时执行

同时变大变色效果:

学新通

class AnimationMultiPage extends StatefulWidget {
    @override
    State<StatefulWidget> createState() => _AnimationMultiPageState();
}

class _AnimationMultiPageState extends State<AnimationMultiPage> with TickerProviderStateMixin {
    late AnimationController _sizeController;
    late AnimationController _colorController;
    late Animation<double> _sizeAnimation;
    late Animation<Color?> _colorAnimation;

    @override
    void initState() {
        super.initState();
        _sizeController = AnimationController(vsync: this, duration: Duration(seconds: 2))
            ..addListener(() {
                setState(() {});
            });
        _sizeAnimation = _sizeController.drive(CurveTween(curve: Curves.linear))
            .drive(Tween(begin: 100, end: 200));

        _colorController = AnimationController(vsync: this, duration: Duration(seconds: 2))
            ..addListener(() {
                setState(() {});
            });
        _colorAnimation = _colorController.drive(CurveTween(curve: Curves.linear))
            .drive(ColorTween(begin: Colors.blue, end: Colors.red));
    }

    @override
    Widget build(BuildContext context) {
        return Scaffold(
            appBar: AppBar(
                title: const Text("同时变大变色"),
            ),
            body: Center(
                child: GestureDetector(
                    onTap: () {
                        _sizeController.forward();
                        _colorController.forward();
                    },
                    child: Container(
                        width: _sizeAnimation.value,
                        height: _sizeAnimation.value,
                        color: _colorAnimation.value,
                        alignment: Alignment.center,
                        child: const Text(
                            "变大变色",
                            style: TextStyle(color: Colors.white, fontSize: 18),
                        ),
                    ),
                ),
            ),
        );
    }

    @override
    void dispose() {
        _sizeController.dispose();
        _colorController.dispose();
        super.dispose();
    }
}
学新通

多动画依次执行

先变大再变色效果:

学新通

class AnimationMulti2Page extends StatefulWidget {
    @override
    State<StatefulWidget> createState() => _AnimationMulti2PageState();
}

class _AnimationMulti2PageState extends State<AnimationMulti2Page> with SingleTickerProviderStateMixin {
    late AnimationController _controller;
    late Animation<double> _sizeAnimation;
    late Animation<Color?> _colorAnimation;

    @override
    void initState() {
        super.initState();
        _controller = AnimationController(vsync: this, duration: Duration(seconds: 2))
            ..addListener(() {
                setState(() {});
            });
        _sizeAnimation = _controller.drive(CurveTween(curve: Interval(0.0, 0.5)))
            .drive(Tween(begin: 100, end: 200));
        _colorAnimation = _controller.drive(CurveTween(curve: Interval(0.5, 1.0)))
            .drive(ColorTween(begin: Colors.blue, end: Colors.red));
    }

    @override
    Widget build(BuildContext context) {
        return Scaffold(
            appBar: AppBar(
                title: const Text("先变大再变色"),
            ),
            body: Center(
                child: GestureDetector(
                    onTap: () {
                        _controller.forward();
                    },
                    child: Container(
                        width: _sizeAnimation.value,
                        height: _sizeAnimation.value,
                        color: _colorAnimation.value,
                        alignment: Alignment.center,
                        child: const Text(
                            "先变大再变色",
                            style: TextStyle(color: Colors.white, fontSize: 18),
                        ),
                    ),
                ),
            ),
        );
    }

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

动画序列

weight:表示每个Tween的权重。

先变大暂停一段再变大效果:

学新通

class AnimationMulti3Page extends StatefulWidget {
    @override
    State<StatefulWidget> createState() => _AnimationMulti3PageState();
}

class _AnimationMulti3PageState extends State<AnimationMulti3Page> with SingleTickerProviderStateMixin {
    late AnimationController _controller;
    late Animation _animation;

    @override
    void initState() {
        super.initState();
        _controller = AnimationController(vsync: this, duration: Duration(seconds: 2))
            ..addListener(() {
                setState(() {});
            });
        _animation = TweenSequence([
            TweenSequenceItem(tween: Tween(begin: 100.0, end: 200.0).chain(CurveTween(curve: Curves.easeIn)), weight: 40),
            TweenSequenceItem(tween: ConstantTween<double>(200.0), weight: 20),
            TweenSequenceItem(tween: Tween(begin: 200.0, end: 300.0), weight: 40),
        ]).animate(_controller);
    }

    @override
    Widget build(BuildContext context) {
        return Scaffold(
            appBar: AppBar(
                title: const Text("先变大暂停一段再变大"),
            ),
            body: Center(
                child: GestureDetector(
                    onTap: () {
                        _controller.forward();
                    },
                    child: Container(
                        width: _animation.value,
                        height: _animation.value,
                        color: Colors.red,
                        alignment: Alignment.center,
                        child: const Text(
                            "先变大暂停一段再变大",
                            style: TextStyle(color: Colors.white, fontSize: 18),
                        ),
                    ),
                ),
            ),
        );
    }

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

Hero

过渡动画。Hero是我们常用的过渡动画,当用户点击一张图片,切换到另一个页面时,这个页面也有此图,那么使用Hero组件就在合适不过了,先看下Hero的效果图:

学新通

第一页

class HeroFirstPage extends StatefulWidget {
    const HeroFirstPage({Key? key}) : super(key: key);

    @override
    State<StatefulWidget> createState() {
        return _HeroFirstPageState();
    }
}

class _HeroFirstPageState extends State<HeroFirstPage> {
    @override
    Widget build(BuildContext context) {
        return Scaffold(
            appBar: AppBar(
                title: const Text("第一页"),
            ),
            body: GridView(
                gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
                    crossAxisCount: 3,
                    crossAxisSpacing: 5,
                    mainAxisSpacing: 3,
                ),
                children: List.generate(10, (index) {
                    return InkWell(
                        onTap: () {
                            Navigator.push(
                                context,
                                PageRouteBuilder(
                                    transitionDuration: const Duration(seconds: 2),
                                    pageBuilder: (BuildContext context, animation, secondaryAnimation) {
                                        return FadeTransition(
                                            opacity: animation,
                                            child: const HeroSecondPage(),
                                        );
                                    },
                                ),
                            );
                        },
                        child: Hero(
                            tag: "hero",
                            child: Container(
                                color: Colors.redAccent,
                                child: Image.asset(
                                    'images/logo.png',
                                ),
                            ),
                        ),
                    );
                }),
            ),
        );
    }
}
学新通

第二页


class HeroSecondPage extends StatelessWidget {
    const HeroSecondPage({Key? key}) : super(key: key);

    @override
    Widget build(BuildContext context) {
        return Scaffold(
            appBar: AppBar(
                title: const Text("第二页"),
            ),
            body: Container(
                alignment: Alignment.center,
                child: Hero(
                    tag: "hero",
                    child: Image.asset(
                        'images/logo.png',
                    ),
                ),
            ),
        );
    }
}
学新通

动画组件

ScaleTransition 缩放动画

学新通

late AnimationController _controller;
late Animation<double> _animation;
_controller = AnimationController(vsync: this, duration: Duration(seconds: 2));
_animation = Tween(begin: 1.0, end: 0.1).animate(_controller);
ScaleTransition(
    scale: _animation,
    child: Container(
        width: 100,
        height: 100,
        color: Colors.red,
        alignment: Alignment.center,
        child: Text("变小"),
    ),
)
//执行动画
_controller.forward();

//重置动画
_controller.reset();

AnimatedOpacity 透明动画

学新通

AnimatedOpacity(
    opacity: _opacity,
    duration: Duration(seconds: 2),
    child: Container(
        width: 100,
        height: 100,
        color: Colors.green,
        alignment: Alignment.center,
        child: Text("透明"),
    ),
)
//执行动画
setState(() {
    _opacity = 0;
});

//重置
setState(() {
    _opacity = 0;
});

SlideTransition 移动动画

学新通

late AnimationController _slideController;
late Animation<Offset> _slideAnimation;
_slideController = AnimationController(vsync: this, duration: const Duration(seconds: 2));
_slideAnimation =
    Tween(begin: const Offset(-1, 0), end: const Offset(0, 0)).animate(_slideController);

SlideTransition(
    position: _slideAnimation,
    child: Container(
        width: 100,
        height: 100,
        color: Colors.yellow,
        alignment: Alignment.center,
        child: const Text("移动"),
    ),
)
学新通
//执行动画
_slideController.forward();

//重置动画
_slideController.reset();

RotationTransition 旋转动画

学新通

late AnimationController _rotationController;
late Animation<double> _rotationAnimation;
_rotationController = AnimationController(vsync: this, duration: const Duration(seconds: 2));
_rotationAnimation = Tween(begin: 0.0, end: 0.5).animate(_rotationController);

RotationTransition(
    alignment: Alignment.center,
    turns: _rotationAnimation,
    child: Container(
        width: 100,
        height: 100,
        color: Colors.pink,
        alignment: Alignment.center,
        child: const Text("旋转"),
    ),
),
学新通
//执行动画
_rotationController.forward();

//重置动画
_rotationController.reset();

AnimatedBuilder 构建简单动画

学新通

_multiController = AnimationController(vsync: this, duration: Duration(seconds: 2));
_colorAnimation = ColorTween(begin: Colors.blue, end: Colors.red).animate(_multiController);
_sizeAnimation = SizeTween(begin: Size(100.0, 50.50), end: Size(50.0, 100.0))
    .animate(_multiController);
AnimatedBuilder(
    animation: _multiController,
    builder: (context, widget) {
        return Container(
            width: _sizeAnimation.value!.width,
            height: _sizeAnimation.value!.height,
            color: _colorAnimation.value,
            alignment: Alignment.center,
            child: Text("变形变色"),
        );
    },
)
//执行动画
_multiController.forward();

//重置
_multiController.reset();

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhfgigjk
系列文章
更多 icon
同类精品
更多 icon
继续加载