王学岗flutter动画

本文介绍了Flutter中两种主要的动画类型:补间动画和基于物理的动画。通过示例代码详细展示了如何创建字体变大、缓动、遮罩、数字变化以及图表和渐隐渐现的动画效果。同时,讲解了AnimationController、Tween和CurvedAnimation等关键概念的使用。
摘要由CSDN通过智能技术生成

动画简介

FLutter中的动画分为两类:补间(tween)动画和基于物理的动画
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
注意Duration(动画持续的时间)的单位是毫秒,2000毫秒就是2秒。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
bounch弹簧效果 ease抖动效果
在这里插入图片描述
注意animate()返回的是一个Animation,而不是一个Animatable
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

代码(一) 字体变大动画

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

  @override
  State<MMM> createState() => _MMMState();
}

class _MMMState extends State<MMM> with SingleTickerProviderStateMixin {
  late Animation<double> tween;
  late AnimationController controller;

  @override
  void initState() {
    super.initState();
    controller = AnimationController(
        duration: const Duration(milliseconds: 4000), vsync: this);
    tween = Tween(begin: 0.0, end: 1.0).animate(controller)
      ..addListener(() {
        setState(() {
          print(tween.value);
        });
      });
    controller.forward();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('动画'),
      ),
      body: GestureDetector(
        onTap: () {
          setState(() {
            controller.forward(from: 0.0);
          });
        },
        child: Center(
          child: Text(
            '字体放大',
            style: TextStyle(fontSize: 60 * controller.value),
          ),
        ),
      ),
    );
  }
}

代码二 缓动动画

在这里插入图片描述
Curveds.fastOutSlowIn 快出慢进
AnimatedBuilder是一个中间件,将Animation和要作用的Widget关联起来。

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

  @override
  State<MMM> createState() => _MMMState();
}

class _MMMState extends State<MMM> with SingleTickerProviderStateMixin {
  late Animation animation; //这里不指定泛型
  late AnimationController controller;
  // 定义时函数类型可以省略 (不建议省略)
  //在 dart 里,被省略的函数返回值不是 void,dart 可以允许你不写函数的返回值,编译器会自动帮助你返回 null
  handler(status) {
    if (status == AnimationStatus.completed) {//监听动画完成状态
      animation.removeStatusListener(handler);//移除监听
      controller.reset();//重置controller
      animation = Tween(begin: 0.0, end: 1.0).animate(
        //使用非线性动画,也就是所谓的插值器,Tween是估值器
          CurvedAnimation(parent: controller, curve: Curves.fastOutSlowIn))
        ..addStatusListener((status) {
          if (status == AnimationStatus.completed) {
            print("两个动画都执行完了");
          }
        });
      controller.forward();//执行第二个动画
    }
  }

  @override
  void initState() {
    super.initState();
    controller =
        AnimationController(duration: const Duration(seconds: 4), vsync: this);
    animation = Tween(begin: -1.0, end: 0.0).animate(
      //使用非线性动画,也就是所谓的插值器,Tween是估值器
        CurvedAnimation(parent: controller, curve: Curves.fastOutSlowIn))
      ..addStatusListener(handler);
  }

  @override
  Widget build(BuildContext context) {
    //计算屏幕的宽度
    final double width = MediaQuery.of(context).size.width;
    controller.forward();
    return Scaffold(
        appBar: AppBar(
          title: const Text('动画'),
        ),
        body: AnimatedBuilder(
          animation: controller,
          builder: (context, child) {
            return Transform(//矩阵转换的方式移动控件
              transform:
              //参数是x,y,z
                  Matrix4.translationValues(animation.value * width, 0, 0),
              //矩阵包裹的内容
              child: Center(
                child: Container(
                  width: 200.0,
                  height: 200.0,
                  color: Colors.green,
                ),
              ),
            );
          },
        ));
  }
  @override
  void dispose() {
    super.dispose();
    //销毁动画
    controller.dispose();
  }
}

代码三遮罩动画

一个容器遮住另一个容器,使用动画叠加

import 'package:flutter/material.dart';

class MaskAnimation extends StatefulWidget {
  _MaskAnimation createState() => _MaskAnimation();
}

class _MaskAnimation extends State<MaskAnimation> with SingleTickerProviderStateMixin {

  AnimationController _controller;
  //需要两个补间对象
  Animation<double> transitionTween;
  Animation<BorderRadius> borderRadius;//给BorderRadius做补间

  @override
  void initState() {
    super.initState();

    _controller = AnimationController(vsync: this, duration: const Duration(seconds: 10),)
              ..addStatusListener((status){//针对controller做监听
                if(status == AnimationStatus.completed){
                  Navigator.pop(context);
                }
              });



    transitionTween = Tween<double>(begin: 50,end: 200).animate(
        CurvedAnimation(
            parent: _controller,
            curve: Curves.ease//
        ),
    );

//一种特殊的tween
    borderRadius = BorderRadiusTween(
        begin: BorderRadius.circular(75.0),
        end: BorderRadius.circular(0.0),
    ).animate(
      CurvedAnimation(
          parent: _controller,
          curve: Curves.ease
      ),
    );
    _controller.forward();

  }



  @override
  Widget build(BuildContext context) {
    final double width = MediaQuery.of(context).size.width;
    _controller.forward();
	//AnimatedBuilder放到最外围
    return AnimatedBuilder(
        animation: _controller,
        builder: (context,child){
        return Scaffold(
          appBar: AppBar(
            title: Text('遮罩动画'),
          ),
          body: Center(
            child: Stack(//放上下两层
              children: <Widget>[
                Center(
                  child: Container(
                    width: 200.0,
                    height: 200.0,
                    color: Colors.black12,
                  ),
                ),
                Center(
                  child: Container(
                    alignment: Alignment.bottomCenter,
                    width: transitionTween.value,
                    height:transitionTween.value,
                    decoration: BoxDecoration(
                      color: Colors.black12,
                      borderRadius: borderRadius.value,
                    ),
                  ),
                ),
              ],
            ),
          ),
        );
    });

  }

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

}

代码三 数字值变化

import 'package:flutter/material.dart';

class ValueAnimation extends StatefulWidget {
  _ValueAnimation createState() => _ValueAnimation();
}

class _ValueAnimation extends State<ValueAnimation> with SingleTickerProviderStateMixin {

  AnimationController controller;
  Animation animation;

  @override
  void initState() {
    super.initState();

    controller = AnimationController(vsync: this, duration: const Duration(seconds: 10),);


    final Animation curve = CurvedAnimation(parent: controller, curve: Curves.easeOut);

    animation = IntTween(begin: 0,end: 10).animate(curve)..addStatusListener((status){
      if(status == AnimationStatus.completed){
        controller.reverse();//完成后反转
      }
      if(status == AnimationStatus.dismissed){
        Navigator.pop(context);
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    controller.forward();
    return AnimatedBuilder(
        animation: controller,
        builder: (context,child){
          return Scaffold(
            appBar: AppBar(
              title: Text('数字变化动画'),
            ),
            body: Center(
              child: Text(animation.value.toString(),style: TextStyle(fontSize: 48.0),),
            ),
          );
    });

  }

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

}

代码4图表动画

import 'package:flutter/material.dart';

class ChartsAnimation extends StatefulWidget {
  _ChartsAnimation createState() => _ChartsAnimation();
}
//不需要with了,因为我们使用了AnimatedContainer,不是自定义
class _ChartsAnimation extends State<ChartsAnimation>{

  var height = 100.0;
  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {

    return Scaffold(
      appBar: AppBar(
        title: Text('图表动画'),
      ),
      body: Center(
        child: Container(
          height: 400,
		  //放在底部
          alignment: AlignmentDirectional.bottomStart,
		  //InkWell带有点击效果
          child: InkWell(
            onTap: (){
              setState(() {
                height = 320;
              });
            },
			//放柱状图
            child: Row(
              crossAxisAlignment: CrossAxisAlignment.end,
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                AnimatedContainer(
                  duration: Duration(seconds: 1),
                  width: 40.0,
                  height: height - 40,
                  color: Colors.greenAccent,
                ),
                AnimatedContainer(
                  margin: EdgeInsets.only(left: 10.0),
                  duration: Duration(seconds: 2),
                  width: 40.0,
                  height: height - 10,
                  color: Colors.yellow,
                ),
                AnimatedContainer(
                  margin: EdgeInsets.only(left: 10.0),
                  duration: Duration(seconds: 3),
                  width: 40.0,
                  height: height - 60,
                  color: Colors.red,
                ),
                AnimatedContainer(
                  margin: EdgeInsets.only(left: 10.0),
                  duration: Duration(seconds: 2),
                  width: 40.0,
                  height: height - 50,
                  color: Colors.blue,
                ),
              ],
            ),
          ),
        ),
      ),
    );

  }


}

代码5 渐隐渐显的动画效果

import 'package:flutter/material.dart';

class OpacityAnimation extends StatefulWidget {
  _OpacityAnimation createState() => _OpacityAnimation();
}

class _OpacityAnimation extends State<OpacityAnimation> {
  bool _visible = true;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('淡入淡出动画'),
      ),
      body: Center(
        child: AnimatedOpacity(
          opacity: _visible ? 1.0 : 0.0,//显示与隐藏,中间的过渡效果由AnimatedOpacity控制。
          duration: Duration(milliseconds: 1000),
          child: Container(
            width: 300.0,
            height: 300.0,
            color: Colors.deepPurple,
          ),
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          setState(
            () {
              _visible = !_visible;
            },
          );
        },
        tooltip: '显示隐藏',
        child: Icon(Icons.add),
      ),
    );
  }
}

页面切换动画效果

import 'package:flutter/material.dart';


class HeroAnimation extends StatelessWidget {


  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('页面切换动画图一'),
      ),
      body: GestureDetector(
        child: Hero(//使用Hero包裹
          tag: '第一张图片',
          child: Image.network(
            "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1541753399410&di=05760e1c65686b018cf28d440a6ddf5c&imgtype=0&src=http%3A%2F%2Fimg1.cache.netease.com%2Fcatchpic%2FD%2FD7%2FD7D7640C07A00D831EFD2AC270ED7FA7.jpg",
          ),
        ),
        onTap: (){
          Navigator.push(context, MaterialPageRoute(builder: (_){
            return DesinationPage();
          }));
        },
      ),

    );
  }
}


class DesinationPage extends StatelessWidget {


  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('页面切换动画图二'),
      ),
      body: GestureDetector(
        child: Hero(
          tag: '第二张图片',
          child: Image.network(
              "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1541753302014&di=9edfe992f8b9d395134fd977dbfeab28&imgtype=0&src=http%3A%2F%2Fimgsrc.baidu.com%2Fimgad%2Fpic%2Fitem%2F2f738bd4b31c870143a3a1dc2c7f9e2f0708fff7.jpg",
          ),
        ),
        onTap: (){
          Navigator.pop(context);
        },
      ),

    );
  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值