Android Flutter实现GIF动画效果的方法详解

目录
  • 前言
  • 交错动画机制
  • 代码实现
  • Interval 介绍
  • 总结

前言

我们之前介绍了不少有关动画的篇章。前面介绍的动画都是只有一个动画效果,那如果我们想对某个组件实现一组动效,比如下面的效果,该怎么办?

staggered animation

这个时候我们需要用到组合动效, Flutter 提供了交错动画(Staggered Animation)的方式实现。对于多个 Anmation 对象,可以共用一个 AnimationController,然后在不同的时间段执行动画效果。这就有点像 GIF 图片一样,一帧帧图像播放实现连续的动画。

交错动画机制

交错动画的实现基于以下几个要点:

  • 所有的 animation对象使用同一个 AnimationController 驱动;
  • 不管实际动画持续的时间长度多长,动画控制器 controller 的值必须在0-1之间;
  • 每个动画对象都有一个0-1范围内的间隔(Interval);
  • 在间隔时间内,Tween 对象从起始值过渡到结束值。
  • 由 AnimationController 统一管理这些Tween 产生的 Animation 对象。

听起来有点抽象,我们以一张图来表述就清晰多了,假设我们有4个动画对象,分别控制组件的透明度(Opacity),宽度(Width),高度(Height)和颜色(Color),交错动画过程如下:

时序示意图

controller 是一个从0到1的归一化的动画控制,其实对应的就是动画时长的归一化。然后 Opacity 透明度动效占据了0-0.25区间;Width 占据了0.25-0.5区间;Height 占据了0.5-0.75区间;最后是 Color 占据了0.75-1.0的区间。区间对应就是动画的时间间隔,只是每个区间内的Tween 动画对象的取值范围都是0-1以控制从起始值到结束值。我们可以理解为是 AnimationController 将多个 Animation 对象按序(也可以重合)拼接起来形成复合形式的动画。

代码实现

看上面的说明是不是觉得还有些难以理解,我们来一段示例代码就很容易明白了。下面的代码我们定义了一个共用的_controller,然后四段动画对象_opaticy_width_height 和_color。其中关键的实现是使用了 Tween 对象的 animate 方法,并指定了一个 CurvedAnimation 对象作为 其parent 参数。而这个CurvedAnimation实际使用 Interval 来切分_controller 的动画时间,从而可以将多个 Animation 对象组合起来。

import 'package:flutter/material.dart';

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

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

class _StaggeredAnimationDemoState extends State<StaggeredAnimationDemo>
    with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  late Animation<double> _opacity;
  late Animation<double> _width;
  late Animation<double> _height;
  late Animation<Color?> _color;

  @override
  void initState() {
    _controller =
        AnimationController(duration: Duration(seconds: 2), vsync: this)
          ..addListener(() {
            setState(() {});
          });
    _opacity = Tween<double>(begin: 0.5, end: 1.0).animate(
      CurvedAnimation(
        parent: _controller,
        curve: Interval(
          0.0,
          0.25,
          curve: Curves.easeIn,
        ),
      ),
    );
    _width = Tween<double>(begin: 0.0, end: 2.0).animate(
      CurvedAnimation(
        parent: _controller,
        curve: Interval(
          0.25,
          0.5,
          curve: Curves.easeIn,
        ),
      ),
    );
    _height = Tween<double>(begin: 0.0, end: 2.0).animate(
      CurvedAnimation(
        parent: _controller,
        curve: Interval(
          0.5,
          0.75,
          curve: Curves.easeIn,
        ),
      ),
    );
    _color = ColorTween(begin: Colors.green, end: Colors.blue).animate(
      CurvedAnimation(
        parent: _controller,
        curve: Interval(
          0.75,
          1.0,
          curve: Curves.easeIn,
        ),
      ),
    );
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('交错动画'),
      ),
      body: Center(
        child: Opacity(
          opacity: _opacity.value,
          child: Container(
            width: 100 + 100 * _width.value,
            height: 100 + 100 * _height.value,
            color: _color.value,
          ),
        ),
      ),
      floatingActionButton: FloatingActionButton(
        child: Icon(Icons.play_arrow),
        onPressed: () {
          if (_controller.isCompleted) {
              _controller.reverse();
            } else if (!_controller.isAnimating) {
              _controller.forward();
          }
        },
      ),
    );
  }
}

我们来看一下运行效果,可以看到运行的动画过程其实就是4段动画效果拼接来的,先是透明度改变,然后是宽度改变,再之后是高度改变,最后是颜色的改变。

运行效果

Interval 介绍

我们来看一下关键的 Interval 类的介绍。

A curve that is 0.0 until [begin], then curved (according to [curve]) from 0.0 at [begin] to 1.0 at [end], then remains 1.0 past [end].

Interval 类继承自 Curve,所不同的是,在 begin 之前曲线的值一直保持为0.0,而在 end 之后一直保持为1.0。所以可以理解为,在 AnimationController 启动动画后,Interval 曲线其实也已经在绘制,只是有效的取值区间只在 begin 到 end 之间,下面就是 Interval 的一种示例曲线图。

image.png

从 Interval 的源码也能看出来,其中 clamp 方法限制了取值范围,当 t <= begin 的时候取值就是0,当 t >= end的时候,取值就是1.0。

@override
double transformInternal(double t) {
  assert(begin >= 0.0);
  assert(begin <= 1.0);
  assert(end >= 0.0);
  assert(end <= 1.0);
  assert(end >= begin);
  t = ((t - begin) / (end - begin)).clamp(0.0, 1.0);
  if (t == 0.0 || t == 1.0)
    return t;
  return curve.transform(t);
}

总结

本篇介绍了交错动画的实现机制和示例,通过交错动画给了我们更多动效组合的空间,从而可以实现类似 GIF图片的那种多帧组合在一起的动画效果。

到此这篇关于Android Flutter实现GIF动画效果的方法详解的文章就介绍到这了,更多相关Android Flutter GIF动画效果内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Android加载Gif动画实现代码

    Android加载Gif动画如何实现?相信大家都很好奇,本文就为大家揭晓,内容如下 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_he

  • Android中播放Gif动画取巧的办法

    由于做的项目,要有个动画的等待效果,第一时间想到的就是Gif(懒,省事),但是试了好多据说能播放Gif的控件,也写过,但是放到魅族手机上就是不能播放,所有就想了个招,既然Gif能在浏览器上播放,那android 的 WebView 也能播放,写了个Demo,果然能播放. 1.将gif的文件放到android的资源文件夹里面 2.写个html,将android的gif源放到WebView里面去加载 <RelativeLayout xmlns:android="http://schemas.a

  • Android 加载GIF图最佳实践方案

    起因 最近在项目中遇到需要在界面上显示一个本地的 GIF 图.按照惯例我直接用了 Glide 框架来实现. Glide 地址: https://github.com/bumptech/glide 我用的 Glide版本为 4.0.0-RC1 , 具体的实现代码如下: Glide.with( this ).asGif().load( R.drawable.yiba_location ).into( location_image ) ; 运行的效果很卡顿,我怀疑是不是方法没有用对,调了压缩模式,还是

  • Android显示GIF图片实例代码

    最近.一个朋友跟我说想,我给她弄个闹钟APP软件...功能其实很简单...只需要弄个简单的闹钟.自己设计设计时间.然后时间到了的时候,闹铃放的声音是男朋友录制好的声音...于是就开始整了.... 第一次做这种的时候.我想把首页界面做成一个GIF动画特效的.这样看起来可爱点...适合妹子用,于是就有了下面这个效果图 上代码 ndroid中的Android.graphics.Movie 这个类,这是android提供给我们的一个非常方便的工具. 首先,重写控件View,自定义一个展示gif图的Gif

  • Android中显示GIF动画的实现代码

    本文实例讲述了Android中显示GIF动画的实现代码.分享给大家供大家参考,具体如下: gif图动画在android中还是比较常用的,比如像新浪微博中,有很多gif图片,而且展示非常好,所以我也想弄一个.经过我多方的搜索资料和整理,终于弄出来了,其实github上有很多开源的gif的展示代码,我下载过几个,但是都不是很理想,不是我完全想要的.所以有时候就得自己学会总结,把开源的东西整理成自己的,现在无聊,也正好有朋友需要,所以现在整理了一下,留着以后备用! 废话不多说,直接上图: 在这里主要用

  • Android自定义View播放Gif动画的示例

    前言 GIF是一种很常见的动态图片格式,在Android中它的使用场景非常多,大到启动页动画.小到一个Loading展示,都可以用GIF动画来完成,使用也很方便,直接从美工那边拿过来用就成.如果项目赶时间或者自定义原生动画太麻烦,GIF都是一个很好的选择,相比于最新的WEBP格式的动画,也有更好的兼容性(毕竟已经出现很多年了). 关于图片加载我一直用的是Google推荐的 Glide,图片加载和缓存都做的很好,同样也支持GIF动画.不过Glide默认就是循环播放Gif,没有开放相关的接口来控制G

  • Android Flutter实现GIF动画效果的方法详解

    目录 前言 交错动画机制 代码实现 Interval 介绍 总结 前言 我们之前介绍了不少有关动画的篇章.前面介绍的动画都是只有一个动画效果,那如果我们想对某个组件实现一组动效,比如下面的效果,该怎么办? staggered animation 这个时候我们需要用到组合动效, Flutter 提供了交错动画(Staggered Animation)的方式实现.对于多个 Anmation 对象,可以共用一个 AnimationController,然后在不同的时间段执行动画效果.这就有点像 GIF

  • Jetpack Compose实现动画效果的方法详解

    目录 概述 低级别动画API animate*AsState 使用Animatable实现颜色变化效果 使用updateTransition实现颜色和圆角动画 rememberInfiniteTransition TargetBasedAnimation 自定义动画 AnimationSpec Easing AnimationVector 高级动画 概述 compose 为支持动画提供了大量的 api,通过这些 api 我们可以轻松实现动画效果 ps:这些 api 的原理与 Flutter 很接

  • jQuery实现基本动画效果的方法详解

    本文实例讲述了jQuery实现基本动画效果的方法.分享给大家供大家参考,具体如下: animate()方法用于创建自定义动画 语法: $(selector).animate({params},speed,callback); params:必须 定义形成动画的CSS属性 speed:可选  规定效果的时常:slow,fast或毫秒 callback:可选  动画完成后所执行的函数名称. jQuery animate()--操作多个属性 默认情况下,所有HTML元素的位置都是静态的,并且无法移动,

  • vue实现购物车抛物线小球动画效果的方法详解

    本文实例讲述了vue实现购物车抛物线小球动画效果的方法.分享给大家供大家参考,具体如下: 先上最终效果图,在商品页面和商品详情页面点击加号添加商品时都可以看到小球抛物线落入购物车的动画效果 此文章只写了商品页面购物小球的实现,商品详情页原理类似 实现步骤: 1. 需要三个组件,最下方包含蓝色购物车的[购物车]组件shopCart.vue(子组件),每个[加减号]组成的购物小球组件cartControl.vue(子组件),和包含每个商品信息的goods组件goods.vue(父组件) 2. 原理,

  • Android Flutter实现3D动画效果示例详解

    目录 前言 AnimatedWidget 简介 3D 旋转动画的实现 总结 前言 上一篇我们介绍了 Animation 和 AnimationController 的使用,这是最基本的动画构建类.但是,如果我们想构建一个可复用的动画组件,通过外部参数来控制其动画效果的时候,上一篇的方法就不太合适了.在 Flutter 中提供了 AnimatedWidget 组件用于构建可复用的动画组件.本篇我们用 AnimatedWidget 来实现组件的3D 旋转效果,如下图所示. AnimatedWidge

  • Android TextView渐变颜色和方向及动画效果的设置详解

    GradientTextView Github点我 一个非常好用的库,使用kotlin实现,用于设置TexView的字体 渐变颜色.渐变方向 和 动画效果 添加依赖 之前仓库发布在 jcenter,但是因为它即将不可用,近期已完成迁移.建议大家使用 mavenCentral 的配置. 使用 jcenter implementation 'com.williamyang:gradienttext:1.0.1' 使用 mavenCentral buildscript { repositories {

  • Android Flutter实现搜索的三种方式详解

    目录 示例 1 :使用搜索表单创建全屏模式 编码 示例 2:AppBar 内的搜索字段(最常见于娱乐应用程序) 编码 示例 3:搜索字段和 SliverAppBar 编码 结论 示例 1 :使用搜索表单创建全屏模式 我们要构建的小应用程序有一个应用程序栏,右侧有一个搜索按钮.按下此按钮时,将出现一个全屏模式对话框.它不会突然跳出来,而是带有淡入淡出动画和幻灯片动画(从上到下).在圆形搜索字段旁边,有一个取消按钮,可用于关闭模式.在搜索字段下方,我们会显示一些搜索历史记录(您可以添加其他内容,如建

  • Android ListView监听滑动事件的方法(详解)

    ListView的主要有两种滑动事件监听方法,OnTouchListener和OnScrollListener 1.OnTouchListener OnTouchListener方法来自View中的监听事件,可以在监听三个Action事件发生时通过MotionEvent的getX()方法或getY()方法获取到当前触摸的坐标值,来对用户的滑动方向进行判断,并可在不同的Action状态中做出相应的处理 mListView.setOnTouchListener(new View.OnTouchLis

  • Android AsyncTask实现异步处理任务的方法详解

    Android AsyncTask实现异步处理任务的方法详解 在开发Android应用时必须遵守单线程模型的原则:Android UI操作并不是线程安全的并且这些操作必须在UI线程中执行. Android 单线程模型概念详解:http://www.jb51.net/article/112165.htm 在单线程模型中始终要记住两条法则: 不要阻塞UI线程 确保只在UI线程中访问Android UI工具包 当一个程序第一次启动时,Android会同时启动一个对应的主线程(Main Thread),

  • Android自定义指示器时间轴效果实例代码详解

    指示器时间轴在外卖.购物类的APP里会经常用到,效果大概就像下面这样,看了网上很多文章,大都是自己绘制,太麻烦,其实通过ListView就可以实现. 在Activity关联的布局文件activity_main.xml中放置一个ListView,代码如下.由于这个列表只是用于展示信息,并不需要用户去点击,所以将其clickable属性置为false:为了消除ListView点击产生的波纹效果,我们设置其listSelector属性的值为透明:我们不需要列表项之间的分割线,所以设置其divider属

随机推荐