iis服务器助手广告广告
返回顶部
首页 > 资讯 > 精选 >如何实现Flutter动画
  • 789
分享到

如何实现Flutter动画

2023-06-04 22:06:32 789人浏览 泡泡鱼
摘要

这篇文章主要为大家展示了“如何实现Flutter动画”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“如何实现Flutter动画”这篇文章吧。动画中的三大核心为了能够实现动画效果,必须提供下面的三个

这篇文章主要为大家展示了“如何实现Flutter动画”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“如何实现Flutter动画”这篇文章吧。

动画中的三大核心

为了能够实现动画效果,必须提供下面的三个元素:

  • Ticker

  • Animation

  • AnimationController

下面对这几个元素进行一下简单的介绍,更详细的在后面说明。

Ticker

简单来说,Ticker 这个类会在常规的一个时间区间里(大约每秒 60 次),发送一个信号,把这想象成你得手表,每秒都会滴答滴答的转。

当 Ticker 启动之后,自从第一个 tick 到来开始,每个到的 tick 都会回调 Ticker 的 callback 方法。

重要提示
尽管所有的 ticker 可能是在不同的时间里启动的,但是它们总是以同步的方式执行,这对于一些同步动画是很有用的。

Animation

Animation 其实没有什么特别的,只不过是一个可以随着动画的生命周期改变的一个值(有特定的类型),值随着动画时间的变化而变化的方式可以是线性的(例如1、2、3、4、5...),也可以更为复杂(参考后面的“Curves 曲线”)。

AnimationController

AnimationController 是一个可以控制一个或多个动画(开始,结束,重复)的控制器。换句话说,它让上面说的 Animation 值在一个指定的时间内,根据一个速度从一个最小值变化到最大。

AnimationController 类介绍

此类可控制动画。为了更加精确,我宁愿说“ 控制一个场景”,因为稍后我们将看到,几个不同的动画可以由同一个控制器来控制……

因此,使用这个AnimationController类,我们可以:

  • 开始一个子动画,正向或者反向播放

  • 停止一个子动画

  • 为子动画设置一个具体的值

  • 定义动画值的边界

以下伪代码可以展示这个类里面的不同的初始化参数

AnimationController controller = new AnimationController(    value:      // the current value of the animation, usually 0.0 (= default)    lowerBound: // the lowest value of the animation, usually 0.0 (= default)    upperBound: // the highest value of the animation, usually 1.0 (= default)    duration:   // the total duration of the whole animation (scene)    vsync:      // the ticker provider    debugLabel: // a label to be used to identify the controller            // during debug session);复制代码

在大多数情况下,初始化 AnimationController 时不会设计到 value,lowerBound,upperBound和debugLabel。

如何将 AnimationController 绑定到 Ticker 上

为了让动画正常工作,必须将 AnimationController 绑定到 Ticker 上。

通常情况下,你可以生成一个 Ticker 绑定到一个 StatefulWidget 实例上。

class _MyStateWidget extends State<MyStateWidget>        with SingleTickerProviderStateMixin {    AnimationController _controller;    @override    void initState(){      super.initState();      _controller = new AnimationController(        duration: const Duration(milliseconds: 1000),         vsync: this,      );    }    @override    void dispose(){      _controller.dispose();      super.dispose();    }    ...}复制代码
  • 第 2 行 这行代码告诉 Flutter ,你想要一个单 Ticker,这个 Ticker 链接到了 MyStateWidget 实例上。

  • 8-10行

控制器的初始化。场景(子动画)的总持续时间设置为1000毫秒,并绑定到了 Ticker(vsync:this)。

隐式参数为:lowerBound = 0.0 和 upperBound = 1.0

  • 16行

非常重要,当 MyStateWidget 这个页面的实例销毁时,您需要释放 controller。

TickerProviderStateMixin 还是 SingleTickerProviderStateMixin?

如果你有几个Animation Controller情况下,你想有不同的 Ticker, 只需要将 SingleTickerProviderStateMixin 替换为 TickerProviderStateMixin。

好的,我已经将控制器绑定到了 Ticker 上,但是它是工作的?

正是由于 ticker,每秒钟将会产生大约 60 个 tick,AnimationController 将根据 tick 在给定的时间里,线性的产生在最小值和最大值之间的值。

在这1000毫秒内产生的值的示例如下:

如何实现Flutter动画

image.png

我们看到值在1000毫秒内从0.0(lowerBound)到1.0(upperBound)变化。生成了51个不同的值。

让我们扩展代码以查看如何使用它。

class _MyStateWidget extends State<MyStateWidget>        with SingleTickerProviderStateMixin {    AnimationController _controller;    @override    void initState(){      super.initState();      _controller = new AnimationController(        duration: const Duration(milliseconds: 1000),         vsync: this,      );      _controller.addListener((){          setState((){});      });      _controller.forward();    }    @override    void dispose(){      _controller.dispose();      super.dispose();    }    @override    Widget build(BuildContext context){        final int percent = (_controller.value * 100.0).round();        return new Scaffold(            body: new Container(                child: new Center(                    child: new Text('$percent%'),                ),            ),        );    }}复制代码
  • 12 行 此行告诉控制器,每次其值更改时,我们都需要重建Widget(通过setState())

  • 第15行

Widget初始化完成后,我们告诉控制器开始计数(forward() -> 从lowerBound到upperBound)

  • 26行

我们检索控制器的值(_controller.value),并且在此示例中,此值的范围是0.0到1.0(也就是 0% 到 100%),我们得到此百分比的整数表达式,将其显示在页面的中心。

动画的概念

如我们所见, controller 可以以线性的方式返回彼此不同的小数值。

有的时候我们可能还有其他的需求如:

  • 使用其他类型的值,例如Offset,int …

  • 使用范围不是从0.0到1.0

  • 考虑线性变化以外的其他变化类型以产生一些效果

使用其他值类型

为了能够使用其他值类型,Animation 类使用模板。

换句话说,您可以定义:

Animation<int> integerVariation;Animation<double> decimalVariation;Animation<Offset> offsetVariation;复制代码
使用不同的数值范围

有时,我们希望使用一个不同的范围,而不是0.0和1.0。

为了定义这样的范围,我们将使用 Tween 类。

为了说明这一点,让我们考虑一个情况,您希望角度从0到π/ 2 变化的情况。

Animation<double> angleAnimation = new Tween(begin: 0.0, end: pi/2);复制代码
变化类型

如前所述,将默认值从 lowerBound 变化到 upperBound 的默认方式是线性的,controller 就是这么控制的。

如果要使角度从0到π/ 2 弧度线性变化,请将 Animation 绑定到AnimationController:

Animation<double> angleAnimation = new Tween(begin: 0.0, end: pi/2).animate(_controller);复制代码

当您开始动画(通过_controller.forward())时,angleAnimation.value 将使用 _controller.value 来获取 范围[0.0; π/ 2] 中的值。

下图显示了这种线性变化(π/ 2 = 1.57)

如何实现Flutter动画

image.png

使用Flutter预定义的曲线变化

Flutter 提供了一组预定义的 Curved 变化,如下:

如何实现Flutter动画

image.png

要使用这些曲线效果:

Animation<double> angleAnimation = new Tween(begin: 0.0, end: pi/2).animate(    new CurvedAnimation(        parent: _controller,        curve:  Curves.ease,        reverseCurve: Curves.easeOut    ));复制代码

这将产生值[0; π/ 2] 之间的值:

  • 当正向播放动画,数值从 0 到 π/2 ,会使用 Curves.ease 效果

  • 当反向播放动画,数值从 π/2 到 0,会使用 Curves.easeOut 效果

控制动画

该AnimationController 类可以让你通过 api 来控制动画。(以下是最常用的API):

  • _controller.forward({两个区间的值})

要求控制器开始生成 lowerBound- > upperBound中的值

from 的可选参数可用于强制控制器从lowerBound之外的另一个值开始“ 计数 ”

  • _controller.reverse({两个区间的值})

要求控制器开始生成 upperBound- > lowerBound中的值

from的可选参数可用于强制控制器从“ upperBound ”之外的另一个值开始“ 计数 ”

  • _controller.stop({bool cancelled:true})

停止运行动画

  • _controller.reset()

将动画重置为从 LowerBound 开始

  • _controller.animateTo(double target, { Duration duration, Curve curve: Curves.linear })

将动画的当前值改变到目标值。

  • _controller.repeat({double min,double max,Duration period})

开始以正向运行动画,并在动画完成后重新启动动画。如果定义了 min 或者 max ,将限制动画的重复执行次数。

安全起见

由于动画可能会意外停止(例如关闭屏幕),因此在使用以下API之一时,添加“ .orCancel ” 更为安全:

__controller.forward().orCancel;复制代码

这个小技巧,可以保证,在 _controller 释放之前,如果 Ticker 取消了,将不会导致异常。

场景的概念

官方文档中不存在“ 场景 ”一词,但就我个人而言,我发现它更接近现实。我来解释一下。

如我所说,一个 AnimationController 管理一个Animation。但是,我们可能将“ 动画 ” 一词理解为一系列需要依次播放或重叠播放的子动画。将子动画组合在一起,这就是我所说的“ 场景 ”。

考虑以下情况,其中动画的整个持续时间为10秒,我们希望达到的效果是:

  • 在开始的2秒内,有一个球从屏幕的左侧移动到屏幕的中间

  • 然后,同一个球需要3秒钟才能从屏幕中心移动到屏幕顶部中心

  • 最终,球需要5秒钟才能消失。 正如您最可能已经想到的那样,我们必须考虑3种不同的动画:

////// Definition of the _controller with a whole duration of 10 seconds///AnimationController _controller = new AnimationController(    duration: const Duration(seconds: 10),     vsync: this);////// First animation that moves the ball from the left to the center///Animation<Offset> moveLeftToCenter = new Tween(    begin: new Offset(0.0, screenHeight /2),     end: new Offset(screenWidth /2, screenHeight /2)).animate(_controller);////// Second animation that moves the ball from the center to the top///Animation<Offset> moveCenterToTop = new Tween(    begin: new Offset(screenWidth /2, screenHeight /2),     end: new Offset(screenWidth /2, 0.0)).animate(_controller);////// Third animation that will be used to change the opacity of the ball to make it disappear///Animation<double> disappear = new Tween(    begin: 1.0,     end: 0.0).animate(_controller);复制代码

现在的问题是,我们如何链接(或编排)子动画?

Interval

组合动画可以通过 Interval 这个类来实现。但是,那什么是 Interval?

可能和我们脑子里首先想到的不一样, Interval 和时间没有关系,而是一组值的范围。

如果考虑使用 _controller,则必须记住,它会使值从 lowerBound 到 upperBound 变化。

通常,这两个值基本定义为 lowerBound = 0.0 和 upperBound = 1.0,这使动画计算更容易,因为[0.0-> 1.0]只是从0%到100%的变化。因此,如果一个场景的总持续时间为10秒,则最有可能在5秒后,相应的_controller.value将非常接近0.5(= 50%)。

如果将3个不同的动画放在一个时间轴上,则可以获得如下示意图:

如何实现Flutter动画

image.png

如果现在考虑值的间隔,则对于3个动画中的每个动画,我们将得到:

  • moveLeftToCenter

持续时间:2秒,从0秒开始,以2秒结束=>范围= [0; 2] =>百分比:从整个场景的0%到20%=> [0.0; 0.20]

  • moveCenterToTop

持续时间:3秒,开始于2秒,结束于5秒=>范围= [2; 5] =>百分比:从整个场景的20%到50%=> [0.20; 0.50]

  • disappear

持续时间:5秒,开始于5秒,结束于10秒=>范围= [5; 10] =>百分比:从整个场景的50%到100%=> [0.50; 1.0]

现在我们有了这些百分比,我们得到每个动画的定义,如下:

////// Definition of the _controller with a whole duration of 10 seconds///AnimationController _controller = new AnimationController(    duration: const Duration(seconds: 10),     vsync: this);////// First animation that moves the ball from the left to the center///Animation<Offset> moveLeftToCenter = new Tween(    begin: new Offset(0.0, screenHeight /2),     end: new Offset(screenWidth /2, screenHeight /2)    ).animate(            new CurvedAnimation(                parent: _controller,                curve:  new Interval(                    0.0,                    0.20,                    curve: Curves.linear,                ),            ),        );////// Second animation that moves the ball from the center to the top///Animation<Offset> moveCenterToTop = new Tween(    begin: new Offset(screenWidth /2, screenHeight /2),     end: new Offset(screenWidth /2, 0.0)    ).animate(            new CurvedAnimation(                parent: _controller,                curve:  new Interval(                    0.20,                    0.50,                    curve: Curves.linear,                ),            ),        );////// Third animation that will be used to change the opacity of the ball to make it disappear///Animation<double> disappear = new Tween(begin: 1.0, end: 0.0)        .animate(            new CurvedAnimation(                parent: _controller,                curve:  new Interval(                    0.50,                    1.0,                    curve: Curves.linear,                ),            ),        );复制代码

这就是定义场景(或一系列动画)所需的全部设置。当然,没有什么可以阻止您重叠子动画…

响应动画状态

有时,获取动画(或场景)的状态很方便。

动画可能具有4种不同的状态:

  • dismissed:动画在开始后停止(或尚未开始)

  • forward:动画从头到尾运行

  • reverse:动画反向播放

  • completed:动画在播放后停止

要获得此状态,我们需要通过以下方式监听动画状态的变化:

   myAnimation.addStatusListener((AnimationStatus status){       switch(status){           case AnimationStatus.dismissed:               ...               break;           case AnimationStatus.forward:               ...               break;           case AnimationStatus.reverse:               ...               break;           case AnimationStatus.completed:               ...               break;       }   });复制代码

状态应用的典型示例就是状态的切换。例如,动画完成后,我们要反转它,如:

  myAnimation.addStatusListener((AnimationStatus status){      switch(status){          ///          /// When the animation is at the beginning, we force the animation to play          ///          case AnimationStatus.dismissed:              _controller.forward();              break;          ///          /// When the animation is at the end, we force the animation to reverse          ///          case AnimationStatus.completed:              _controller.reverse();              break;      }  });复制代码

理论已经足够了,现在我们开始实战

我在文章开头提到了一个动画,现在我准备开始实现它,名字就叫“guillotine(断头台)”

动画分析及程序初始化

未来能够实现“斩头台”效果,我们需要考虑一下几个方面:

  • 页面内容本身

  • 当我们点击菜单图标时,菜单栏会旋转

  • 旋转时,菜单会覆盖页面内容并填充整个视口

  • 一旦菜单是完全可见,我们再次点击图标,菜单旋转出来,以便回到原来的位置和尺寸

从这些观察中,我们可以立即得出结论,我们没有使用带有AppBar的普通Scaffold(因为后者是固定的)。

我们需要使用 2 层 Stack:

  • 页面内容(下层)

  • 菜单(上层)

程序的基本框架基本出来了:

class MyPage extends StatefulWidget {    @override    _MyPageState createState() => new _MyPageState();}class _MyPageState extends State<MyPage>{  @override  Widget build(BuildContext context){      return SafeArea(        top: false,        bottom: false,        child: new Container(          child: new Stack(            alignment: Alignment.topLeft,            children: <Widget>[              new Page(),              new GuillotineMenu(),            ],          ),        ),      );  }}class Page extends StatelessWidget {    @override    Widget build(BuildContext context){        return new Container(            padding: const EdgeInsets.only(top: 90.0),            color: Color(0xff222222),        );    }}class GuillotineMenu extends StatefulWidget {    @override    _GuillotineMenuState createState() => new _GuillotineMenuState();}class _GuillotineMenuState extends State<GuillotineMenu> {    @overrride    Widget build(BuildContext context){        return new Container(            color: Color(0xff333333),        );    }}复制代码

这些代码的运行结果为黑屏,仅显示覆盖整个视口的GuillotineMenu。

菜单效果分析

如果你看了上面的示例,可以看到菜单完全打开时,它完全覆盖了视口。打开后,只有可见的AppBa。

而如果最初旋转 GuillotineMenu 并在按下菜单按钮时将其旋转π/ 2,将会怎样呢,如下图所示这样吗?

如何实现Flutter动画

image.png

然后,我们可以按以下方式重写_GuillotineMenuState类:(这里不在解释如何布局,这不是重点)

class _GuillotineMenuState extends State<GuillotineMenu> {   double rotationAngle = 0.0;    @override    Widget build(BuildContext context){        MediaQueryData mediaQueryData = MediaQuery.of(context);        double screenWidth = mediaQueryData.size.width;        double screenHeight = mediaQueryData.size.height;        return new TransfORM.rotate(                angle: rotationAngle,                origin: new Offset(24.0, 56.0),                alignment: Alignment.topLeft,                child: Material(                    color: Colors.transparent,                    child: Container(                    width: screenWidth,                    height: screenHeight,                    color: Color(0xFF333333),                    child: new Stack(                        children: <Widget>[                            _buildMenuTitle(),                            _buildMenuIcon(),                            _buildMenuContent(),                        ],                    ),                ),            ),        );    }    ///    /// Menu Title    ///    Widget _buildMenuTitle(){        return new Positioned(            top: 32.0,            left: 40.0,            width: screenWidth,            height: 24.0,            child: new Transform.rotate(                alignment: Alignment.topLeft,                origin: Offset.zero,                angle: pi / 2.0,                child: new Center(                child: new Container(                    width: double.infinity,                    height: double.infinity,                    child: new Opacity(                    opacity: 1.0,                    child: new Text('ACTIVITY',                        textAlign: TextAlign.center,                        style: new TextStyle(                            color: Colors.white,                            fontSize: 20.0,                            fontWeight: FontWeight.bold,                            letterSpacing: 2.0,                        )),                    ),                ),            )),        );    }    ///    /// Menu Icon    ///     Widget _buildMenuIcon(){        return new Positioned(            top: 32.0,            left: 4.0,            child: new IconButton(                icon: const Icon(                    Icons.menu,                    color: Colors.white,                ),                onPressed: (){},            ),        );    }    ///    /// Menu content    ///    Widget _buildMenuContent(){        final List<Map> _menus = <Map>[            {            "icon": Icons.person,            "title": "profile",            "color": Colors.white,            },            {            "icon": Icons.view_agenda,            "title": "feed",            "color": Colors.white,            },            {            "icon": Icons.swap_calls,            "title": "activity",            "color": Colors.cyan,            },            {            "icon": Icons.settings,            "title": "settings",            "color": Colors.white,            },        ];        return new Padding(            padding: const EdgeInsets.only(left: 64.0, top: 96.0),            child: new Container(                width: double.infinity,                height: double.infinity,                child: new Column(                    mainAxisAlignment: MainAxisAlignment.start,                    children: _menus.map((menuItem) {                        return new ListTile(                            leading: new Icon(                            menuItem["icon"],                            color: menuItem["color"],                            ),                            title: new Text(                            menuItem["title"],                            style: new TextStyle(                                color: menuItem["color"],                                fontSize: 24.0),                            ),                        );                    }).toList(),                ),            ),        );    }}复制代码
  • 10-13行

这些线定义了断头台菜单围绕旋转中心(菜单图标的位置)的旋转

现在,此代码的结果将显示一个未旋转的菜单屏幕(因为rotationAngle = 0.0),该屏幕显示了垂直的标题。

接下来使 menu 显示动画

如果更新 rotationAngle 的值(在-π/ 2和0之间),您将看到菜单旋转了相应的角度。

如前所述,我们需要

  • 一个SingleTickerProviderStateMixin,因为我们只有1个场景

  • 一个AnimationController

  • 一个动画 有一个角度变化

代码如下所示:

class _GuillotineMenuState extends State<GuillotineMenu>    with SingleTickerProviderStateMixin {    AnimationController animationControllerMenu;    Animation<double> animationMenu;    ///    /// Menu Icon, onPress() handling    ///    _handleMenuOpenClose(){        animationControllerMenu.forward();    }    @override    void initState(){        super.initState();    ///        /// Initialization of the animation controller        ///        animationControllerMenu = new AnimationController(            duration: const Duration(milliseconds: 1000),             vsync: this        )..addListener((){            setState((){});        });    ///        /// Initialization of the menu appearance animation        ///        _rotationAnimation = new Tween(            begin: -pi/2.0,             end: 0.0        ).animate(animationControllerMenu);    }    @override    void dispose(){        animationControllerMenu.dispose();        super.dispose();    }    @override    Widget build(BuildContext context){        MediaQueryData mediaQueryData = MediaQuery.of(context);        double screenWidth = mediaQueryData.size.width;        double screenHeight = mediaQueryData.size.height;        double angle = animationMenu.value;        return new Transform.rotate(            angle: angle,            origin: new Offset(24.0, 56.0),            alignment: Alignment.topLeft,            child: Material(                color: Colors.transparent,                child: Container(                    width: screenWidth,                    height: screenHeight,                    color: Color(0xFF333333),                    child: new Stack(                        children: <Widget>[                            _buildMenuTitle(),                            _buildMenuIcon(),                            _buildMenuContent(),                        ],                    ),                ),            ),        );    }    ...    ///    /// Menu Icon    ///     Widget _buildMenuIcon(){        return new Positioned(            top: 32.0,            left: 4.0,            child: new IconButton(                icon: const Icon(                    Icons.menu,                    color: Colors.white,                ),                onPressed: _handleMenuOpenClose,            ),        );    }    ...}复制代码

现在,当我们按下菜单按钮时,菜单会打开,但再次按下按钮时菜单不会关闭。这是 AnimationStatus 要完成的事情。

让我们添加一个监听器,并基于 AnimationStatus 决定是向前还是向后运行动画。

////// Menu animation status///enum _GuillotineAnimationStatus { closed, open, animating }class _GuillotineMenuState extends State<GuillotineMenu>    with SingleTickerProviderStateMixin {    AnimationController animationControllerMenu;    Animation<double> animationMenu;    _GuillotineAnimationStatus menuAnimationStatus = _GuillotineAnimationStatus.closed;    _handleMenuOpenClose(){        if (menuAnimationStatus == _GuillotineAnimationStatus.closed){            animationControllerMenu.forward().orCancel;        } else if (menuAnimationStatus == _GuillotineAnimationStatus.open) {            animationControllerMenu.reverse().orCancel;        }    }    @override    void initState(){        super.initState();    ///        /// Initialization of the animation controller        ///        animationControllerMenu = new AnimationController(            duration: const Duration(milliseconds: 1000),             vsync: this        )..addListener((){            setState((){});        })..addStatusListener((AnimationStatus status) {            if (status == AnimationStatus.completed) {        ///        /// When the animation is at the end, the menu is open        ///              menuAnimationStatus = _GuillotineAnimationStatus.open;            } else if (status == AnimationStatus.dismissed) {        ///        /// When the animation is at the beginning, the menu is closed        ///              menuAnimationStatus = _GuillotineAnimationStatus.closed;            } else {        ///        /// Otherwise the animation is running        ///              menuAnimationStatus = _GuillotineAnimationStatus.animating;            }          });    ...    }...}复制代码

现在菜单可以按预期方式打开或关闭,但是前面的演示向我们展示了一个打开/关闭的动画,该懂哈不是线性的,看起来有一个反复的回弹效果。接下来让我们添加此效果。

为此,我将选择以下2种效果:

  • 菜单打开时用 bounceOut

  • 菜单关闭时用 bouncIn

如何实现Flutter动画

image.png

如何实现Flutter动画

image.png

class _GuillotineMenuState extends State<GuillotineMenu>    with SingleTickerProviderStateMixin {...    @override    void initState(){    ...    ///    /// Initialization of the menu appearance animation    ///     animationMenu = new Tween(        begin: -pi / 2.0,         end: 0.0    ).animate(new CurvedAnimation(        parent: animationControllerMenu,        curve: Curves.bounceOut,        reverseCurve: Curves.bounceIn,    ));    }...}复制代码

在此实现中仍有一些细节没有实现:打开菜单时标题消失,而关闭菜单时显示标题。这是一个面朝上/朝外的效果,也要作为动画处理。让我们添加它。

class _GuillotineMenuState extends State<GuillotineMenu>    with SingleTickerProviderStateMixin {  AnimationController animationControllerMenu;  Animation<double> animationMenu;  Animation<double> animationTitleFadeInOut;  _GuillotineAnimationStatus menuAnimationStatus;...  @override  void initState(){    ...    ///    /// Initialization of the menu title fade out/in animation    ///     animationTitleFadeInOut = new Tween(        begin: 1.0,         end: 0.0    ).animate(new CurvedAnimation(        parent: animationControllerMenu,        curve: new Interval(            0.0,            0.5,            curve: Curves.ease,        ),    ));  }...  ///  /// Menu Title  ///  Widget _buildMenuTitle(){    return new Positioned(      top: 32.0,      left: 40.0,      width: screenWidth,      height: 24.0,      child: new Transform.rotate(        alignment: Alignment.topLeft,        origin: Offset.zero,        angle: pi / 2.0,        child: new Center(          child: new Container(            width: double.infinity,            height: double.infinity,              child: new Opacity(                opacity: animationTitleFadeInOut.value,                child: new Text('ACTIVITY',                    textAlign: TextAlign.center,                    style: new TextStyle(                        color: Colors.white,                        fontSize: 20.0,                        fontWeight: FontWeight.bold,                        letterSpacing: 2.0,                    )),                ),            ),        )),    );  }...}复制代码

最终的效果基本如下:

如何实现Flutter动画

以上是“如何实现Flutter动画”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注编程网精选频道!

--结束END--

本文标题: 如何实现Flutter动画

本文链接: https://www.lsjlt.com/news/240303.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 如何实现Flutter动画
    这篇文章主要为大家展示了“如何实现Flutter动画”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“如何实现Flutter动画”这篇文章吧。动画中的三大核心为了能够实现动画效果,必须提供下面的三个...
    99+
    2023-06-04
  • Android Flutter如何实现3D动画效果
    这篇文章主要讲解了“Android Flutter如何实现3D动画效果”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Android Flutter如何实现3D动画效果”吧...
    99+
    2023-06-29
  • Flutter实现抽屉动画
    这篇会深化View拖拽实例,利用Flutter Animation、插值器以及AnimatedBuilder教大家实现带动画的抽屉效果。先来看效果: 通过构思,我们可以设想到实现抽...
    99+
    2024-04-02
  • Flutter实现心动的动画特效
    目录实现动画混入 SingleTickerProviderStateMixin创建动画抽离成小组件完整代码为了追求更好的用户体验,有时候我们需要一个类似心跳一样跳动着的控件来吸引用户...
    99+
    2024-04-02
  • flutter如何实现带删除动画的listview功能
    这篇文章将为大家详细讲解有关flutter如何实现带删除动画的listview功能,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。个人开发app中,需要开发一个带有删除功能的ListView效果如下需求动画...
    99+
    2023-06-15
  • 如何基于Flutter实现爱心三连动画效果
    这篇文章主要为大家展示了“如何基于Flutter实现爱心三连动画效果”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“如何基于Flutter实现爱心三连动画效果”这篇文章吧。前言我们开始 Flutt...
    99+
    2023-06-29
  • Flutter使用AnimatedOpacity实现图片渐现动画
    目录前言AnimatedOpacity 简介AnimatedOpacity 应用图片渐现过渡总结前言 我们介绍了几篇 Flutter 的动画控制类,相信大家对动画也有了一定的了解,可...
    99+
    2024-04-02
  • Flutter Animation实现缩放和滑动动画效果
    本文实例为大家分享了Flutter Animation实现缩放和滑动动画的具体代码,供大家参考,具体内容如下 Animation对象是Flutter动画库中的一个核心类,它生成指导动...
    99+
    2024-04-02
  • flutter实现带删除动画的listview功能
    个人开发app中,需要开发一个带有删除功能的ListView 效果如下 需求动画分析 列表可以滚动用listView, 有两个动画,第一个动画是透明度变化,第二个是size变化 是...
    99+
    2024-04-02
  • css3如何实现动画
    css3实现动画的方法:1、在通过transition设置过渡,添加transform设置形状,从而可以实现动画效果;2、添加animation属性,设置动画效果即可。具体使用示例:通过transition设置过渡,添加transform设...
    99+
    2024-04-02
  • Angular如何实现动画
    这篇文章给大家分享的是有关Angular如何实现动画的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。在实现的过程上,我采用了两种不同的 Angular 动画的方式:使用 TypeS...
    99+
    2024-04-02
  • CSS3动画如何实现
    本篇内容主要讲解“CSS3动画如何实现”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“CSS3动画如何实现”吧!我们先来看看示例 注意: 这里呢,我们用 my...
    99+
    2024-04-02
  • 如何实现svg动画
    这篇文章主要为大家展示了“如何实现svg动画”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“如何实现svg动画”这篇文章吧。   一、SVG 的 animati...
    99+
    2024-04-02
  • Flutter使用AnimatedSwitcher实现场景切换动画
    目录前言AnimatedSwitcher 介绍应用总结前言 在应用中,我们经常会遇到切换组件的场景,比如点击一个按钮后,将当前的图片为另一张图片;或者是翻转卡片,显示卡片详情。在 F...
    99+
    2024-04-02
  • Flutter Component动画的显和隐怎么实现
    这篇文章主要讲解了“Flutter Component动画的显和隐怎么实现”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Flutter Component动画的显和隐怎么...
    99+
    2023-07-05
  • Flutter怎么实现不同缩放动画效果
    本篇内容主要讲解“Flutter怎么实现不同缩放动画效果”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Flutter怎么实现不同缩放动画效果”吧!需求背景组件缩放可以向着一个方向进行缩放,放大列...
    99+
    2023-07-02
  • Flutter怎么实现添加页面过渡动画
    本篇内容介绍了“Flutter怎么实现添加页面过渡动画”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!使用插件探索不同的转换步骤 1: 在 p...
    99+
    2023-06-30
  • Flutter实现不同缩放动画效果详解
    目录需求背景可缩放组件介绍ScaleTransitionSizeTransitionAnimatedSizeAnimatedBuilder小结需求背景 组件缩放可以向着一个方向进行缩...
    99+
    2024-04-02
  • Android Flutter怎么实现仿闲鱼动画效果
    这篇文章主要讲解了“Android Flutter怎么实现仿闲鱼动画效果”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Android Flutter怎么实现仿闲鱼动画效果...
    99+
    2023-07-05
  • uniapp 如何实现canvas动画
    随着移动端应用的不断发展,动画已经成为了现代应用的必备元素。而canvas作为HTML5中提供的一种绘图技术,被广泛应用于实现各种复杂的动画效果。而今,随着uniapp的流行,我们也可以借助uniapp的强大能力,轻松实现canvas动画效...
    99+
    2023-05-22
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作