flutter lottie animation progress bar 美丽多彩生动的动画进度条

flutter lottie animation progress bar 美丽多彩生动的动画进度条

flutter支持使用lottie动画,有了lottie,我们也可以在flutter中实现很多炫酷的动画效果,这次为我们就来学习使用lottie动画,实现一个显示系统内存使用状态的动画进度条。本文将涉及到lottie动画播放控制、Isoalte多线程、系统信息获取等知识。

Lottie

Lottie 是 Airbnb 开源的一套跨平台的完整的动画效果解决方案,是一种基于 JSON 的动画文件格式,设计师可以使用 Adobe After Effects 设计出漂亮的动画并导出成 JSON 格式,允许您在任何平台上发布动画,就像交付静态资产一样容易。它们是在任何设备上都可以使用的小文件。LottieFiles 允许您以最简单的方式创建、编辑、测试、协作和交付 Lottie。

文件大小

与其他格式(如 GIF 或 MP4)相比,Lottie 动画要小得多,同时保持相同的质量。

无限可扩展

Lottie 动画基于矢量,这意味着您可以放大和缩小它们,而不必担心分辨率。

多平台支持和库

对于所有开发人员来说,Lottie 交接非常容易。您可以在iOS,Android,Web和React Native上使用Lottie动画,而无需修改。

互动

在 Lottie 动画中,动画元素是公开的,因此您可以操作它们以使其具有交互性并响应滚动、单击和悬停等交互。

Lottie for Flutter

Lottie for Flutter适用于Android,iOS,macOS,linux,Windows和Web。插件地址:github.com/xvrh/lottie...。在flutter中使用lottie也很简单,可以使用Lottie.asset设置本地资源,也可以使用Lottie.network设置网络lottie资源。如下代码所示:

scala 复制代码
import 'package:flutter/material.dart';
import 'package:lottie/lottie.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: ListView(
          children: [
            // Load a Lottie file from your assets
            Lottie.asset('assets/LottieLogo1.json'),

            // Load a Lottie file from a remote url
            Lottie.network(
                'https://raw.githubusercontent.com/xvrh/lottie-flutter/master/example/assets/Mobilo/A.json'),

            // Load an animation and its images from a zip file
            Lottie.asset('assets/lottiefiles/angel.zip'),
          ],
        ),
      ),
    );
  }
}

lottie animation progress bar 动画进度条

lottie动画文件下载使用

接下来我们来实现一个动画进度条来显示内存使用情况。首先到lottiefiles.com/上找一些免费的lottie进度条动画文件下载下来使用。放到我们的本地文件夹中,还需要在pubspec.yaml文件中对本地资源进行设置。

yaml 复制代码
flutter:

  # The following line ensures that the Material Icons font is
  # included with your application, so that you can use the icons in
  # the material Icons class.
  uses-material-design: true

  # To add assets to your application, add an assets section, like this:
  assets:
      - assets/
  #   - images/a_dot_burr.jpeg
  #   - images/a_dot_ham.jpeg

接着使用 Lottie.asset()导入本地lottie动画资源, 导入本地动画资源时还可以通过 width、height属性设置要显示的动画的大小。使用Column组件放在外层,这样我们就可以将四个lottie动画文件竖着展示出来。结合使用Padding和Center组件来调整动画显示的位置,让他看起来顺眼一些。

scala 复制代码
 
class MyApp extends StatefulWidget {
  const MyApp({super.key});

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> with TickerProviderStateMixin {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          children: [
            const Padding(padding: EdgeInsets.all(20)),
            Lottie.asset(
              'assets/78495-progress.json',
              width: 150,
              height: 150,
            ),
            Lottie.asset(
              'assets/88697-neomorphism-radial-progress-bar-style-2-light-theme-01.json',
              width: 150,
              height: 150,
            ),
            Lottie.asset(
              'assets/91938-green-progress-bar-without-popover.json',
              width: 200,
              height: 150,
            ),
            Lottie.asset(
              'assets/93125-progress-bar.json',
              width: 300,
              height: 100,
            ),
          ],
        ),
      ),
    );
  }
}

效果图:

lottie动画播放控制

实际使用的环境会很复杂,我们需要控制动画的播放状态,lottie可以使用AnimationController控制动画的播放。首先定义late final AnimationController _controller;动画控制器,然后在asset中指定我们声明的控制器,这样我们就可以在外部使用_controller控制动画的播放状态。

less 复制代码
 Lottie.asset(
    'assets/78495-progress.json',
    width: 150,
    height: 150,
    controller: _controller,
    onLoaded: (composition) {
    setState(() {
   _controller.duration = composition.duration;
     });
    },
 ),

为了控制动画播放,我们需要添加一些按钮,点击按钮时对动画的播放状态进行控制,使用Row组件横向包裹三个TextButton按钮,分别控制动画播放状态的前进、停止、后退,设置 mainAxisAlignment: MainAxisAlignment.center,居中显示按钮。只要使用_controller.forward();_controller.stop();_controller.reverse();按个控制器方法就可以分别控制动画的前进、停止、后退。

less 复制代码
Row(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        TextButton(
          onPressed: () {
            _controller.forward();
          },
          child: Text("前进"),
        ),
        TextButton(
          onPressed: () {
            _controller.stop();
          },
          child: Text("暂停"),
        ),
        TextButton(
          onPressed: () {
            _controller.reverse();
          },
          child: Text("后退"),
        ),
      ],
    )

效果图:

内存使用状态展示

我们使用system_info2插件来读取内存使用状态,本来想同时显示CPU使用率,但是找了半天没找到Windows下读取CPU使用率的插件,还是很遗憾的。因为使用system_info2读取内存比较耗费时间,导致我们的UI会有卡顿,所以我要新建一个Isolate来读取我们的内存状态,在新isolate中设置定时器,定时读取内存状态,计算出内存使用率,并将结果发回到UI Isoalte,通知UI进行页面更新。在UI Isolate中 使用receivePort.listen监听新isolate发回来的结果,利用此结果控制动画的播放。_controller.animateTo_controller.animateBack可以控制动画正向或者逆向播放到某一帧,这正是我所需要的。

ini 复制代码
void makenewisolate() {
  ReceivePort receivePort = ReceivePort();
  Isolate.spawn(newisolate, receivePort.sendPort);
  receivePort.listen((message) {
    if (message > _controller.value) {
      _controller.animateTo(message);
    }
    if (message < _controller.value) {
      _controller.animateBack(message);
    }
  });
}

void newisolate(SendPort sendPort) {
  var timer = Timer.periodic(const Duration(seconds: 2), (timer) {
    const int megaByte = 1024 * 1024;
    var last = 1 -
        ((SysInfo.getFreePhysicalMemory() ~/ megaByte) /
            (SysInfo.getTotalPhysicalMemory() ~/ megaByte));
    sendPort.send(last);
  });
}

效果图:

可以看到,我们的进度条会随着内存的使用情况进行变化,反应出内存的使用情况。图中四个进度条只有后两个比较如实的反应内存使用情况,前两个动画显示的百分比不是很正确,这是由于前两个动画不是从0%开始的,都有一个前摇,导致百分比无法完全对应,后续可以针对问题再进行优化。

总结

这次简单的学习了lottie动画在flutetr中的使用、控制方法,效果还是很不错的。同时还涉及到了flutter多线程Isolate的使用。后续让我们一起继续深入学习吧。

完整代码:

less 复制代码
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:system_info2/system_info2.dart';
import 'package:lottie/lottie.dart';
import 'dart:isolate';

late final AnimationController _controller;

void main() async {
  makenewisolate();
  runApp(const Homepage());
}

void makenewisolate() {
  ReceivePort receivePort = ReceivePort();
  Isolate.spawn(newisolate, receivePort.sendPort);
  receivePort.listen((message) {
    if (message > _controller.value) {
      _controller.animateTo(message);
    }
    if (message < _controller.value) {
      _controller.animateBack(message);
    }
  });
}

void newisolate(SendPort sendPort) {
  var timer = Timer.periodic(const Duration(seconds: 2), (timer) {
    const int megaByte = 1024 * 1024;
    var last = 1 -
        ((SysInfo.getFreePhysicalMemory() ~/ megaByte) /
            (SysInfo.getTotalPhysicalMemory() ~/ megaByte));
    sendPort.send(last);
  });
}

class Homepage extends StatelessWidget {
  const Homepage({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        useMaterial3: true,
      ),
      home: const Scaffold(
        body: MyApp(),
      ),
    );
  }
}

class MyApp extends StatefulWidget {
  const MyApp({super.key});

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> with TickerProviderStateMixin {
  @override
  void initState() {
    super.initState();
    _controller = AnimationController(vsync: this);
  }

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          children: [
            const Padding(padding: EdgeInsets.all(20)),
            Lottie.asset(
              'assets/78495-progress.json',
              width: 150,
              height: 150,
              controller: _controller,
              onLoaded: (composition) {
                setState(() {
                  _controller.duration = composition.duration;
                });
              },
            ),
            Lottie.asset(
              'assets/88697-neomorphism-radial-progress-bar-style-2-light-theme-01.json',
              width: 150,
              height: 150,
              controller: _controller,
              onLoaded: (composition) {
                setState(() {
                  _controller.duration = composition.duration;
                });
              },
            ),
            Lottie.asset(
              'assets/91938-green-progress-bar-without-popover.json',
              width: 200,
              height: 150,
              controller: _controller,
              onLoaded: (composition) {
                setState(() {
                  _controller.duration = composition.duration;
                });
              },
            ),
            Lottie.asset(
              'assets/93125-progress-bar.json',
              width: 300,
              height: 100,
              controller: _controller,
              onLoaded: (composition) {
                setState(() {
                  _controller.duration = composition.duration;
                });
              },
            ),
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                TextButton(
                  onPressed: () {
                    _controller.forward();
                  },
                  child: Text("前进"),
                ),
                TextButton(
                  onPressed: () {
                    _controller.stop();
                  },
                  child: Text("暂停"),
                ),
                TextButton(
                  onPressed: () {
                    _controller.reverse();
                  },
                  child: Text("后退"),
                ),
              ],
            )
          ],
        ),
      ),
    );
  }
}
相关推荐
柏箱2 分钟前
使用JavaScript写一个网页端的四则运算器
前端·javascript·css
TU^3 分钟前
C语言习题~day16
c语言·前端·算法
一切皆是定数28 分钟前
Android车载——VehicleHal初始化(Android 11)
android·gitee
一切皆是定数30 分钟前
Android车载——VehicleHal运行流程(Android 11)
android
problc30 分钟前
Android 组件化利器:WMRouter 与 DRouter 的选择与实践
android·java
图王大胜1 小时前
Android SystemUI组件(11)SystemUIVisibility解读
android·framework·systemui·visibility
学习使我快乐013 小时前
JS进阶 3——深入面向对象、原型
开发语言·前端·javascript
bobostudio19953 小时前
TypeScript 设计模式之【策略模式】
前端·javascript·设计模式·typescript·策略模式
黄尚圈圈4 小时前
Vue 中引入 ECharts 的详细步骤与示例
前端·vue.js·echarts