flutter开发实战-flutter播放PAG动画

news2025/2/23 3:34:42

flutter开发实战-flutter播放PAG动画

最近开发过程中,遇到了PAG动画,这里进行记录一下。
在这里插入图片描述

一、什么是PAG?

官网:https://pag.art/
Portable Animated Graphics 是一套完整的动效工作流解决方案。
目标是降低或消除动效相关的研发成本,能够一键将设计师在 AE(Adobe After Effects)中制作的动效内容导出成素材文件,并快速上线应用于几乎所有的主流平台。

类似SVGA,PAG通过二进制的方式效率更高。目前PAG sdk有iOS、Android、web端。在flutter端,有一个pag插件。pag插件在原生端使用的是iOS、Android端的PAG sdk,通过texture外接纹理的方式进行播放PAG动画。(很遗憾,目前flutter上PAG的1.0.4版本中源码没看到替换占位图、替换文本图层的代码。)

期待后续的版本

二、使用PAG插件

在工程中的pubspec.yaml文件中引入插件

  # pag动画
  pag: ^1.0.4
    

播放网络PAG动画


PAGView.network(
                "https://svipwebwx-30096.sz.gfp.tencent-cloud.com/file1647585475981.pag",
                repeatCount: PAGView.REPEAT_COUNT_LOOP,
                initProgress: 0.25,
                autoPlay: true,
                key: networkPagKey,
              ),
    

可以通过监听onAnimationStart、onAnimationEnd、onAnimationRepeat、onAnimationCancel

通过使用key的state进行主动调用


final GlobalKey<PAGViewState> pagKey = GlobalKey<PAGViewState>();
  
  //传入key值
  PAGView.url(key:pagKey)
  
  //播放
  pagKey.currentState?.start();
  
  //暂停
  pagKey.currentState?.pause();  
  
  //停止
  pagKey.currentState?.stop();  
  
  //设置进度
  pagKey.currentState?.setProgress(xxx);
  
  //获取坐标位置的图层名list
  pagKey.currentState?.getLayersUnderPoint(x,y);
    

三、完整示例代码

完整示例代码如下

import 'dart:typed_data';

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:pag/pag.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: MyHome(),
    );
  }
}

class MyHome extends StatefulWidget {
  @override
  _MyHomeState createState() => _MyHomeState();
}

class _MyHomeState extends State<MyHome> {

  GlobalKey<PAGViewState> _fansDanceKey = GlobalKey<PAGViewState>(debugLabel: _assetFans);
  GlobalKey<PAGViewState> _assetDanceKey = GlobalKey<PAGViewState>(debugLabel: _assetFans);
  GlobalKey<PAGViewState> get assetPagKey => _pagAsset == _assetFans ? _fansDanceKey : _assetDanceKey;

  final GlobalKey<PAGViewState> networkPagKey = GlobalKey<PAGViewState>();
  final GlobalKey<PAGViewState> bytesPagKey = GlobalKey<PAGViewState>();

  Uint8List? bytesData;

  // 本地加载资源
  static const String _assetFans = 'data/fans.pag';
  static const String _assetDance = 'data/dance.pag';
  static const String _assetError = 'data/error.pag';
  String _pagAsset = _assetFans;

  void changeAsset() {
    setState(() {
      _pagAsset = _pagAsset == _assetFans ? _assetDance : _assetFans;
    });
  }

  @override
  void initState() {
    rootBundle.load("data/fans.pag").then((data) {
      setState(() {
        bytesData = Uint8List.view(data.buffer);
      });
    });
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: const Text('PAGView example app'),
        ),
        body: SingleChildScrollView(
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              ///TODO: PAGView加载本地资源
              Padding(
                padding: EdgeInsets.only(top: 20, left: 12, bottom: 20),
                child: Text(
                  "PAGView加载本地资源:",
                  style: TextStyle(fontSize: 16, fontWeight: FontWeight.w500, color: Colors.black54),
                ),
              ),
              SizedBox(
                width: 100,
                height: 100,
                child: PAGView.asset(
                  _pagAsset,
                  repeatCount: PAGView.REPEAT_COUNT_LOOP,
                  initProgress: 0.25,
                  autoPlay: true,
                  key: assetPagKey,
                ),
              ),
              Padding(
                padding: EdgeInsets.only(left: 12, top: 10),
                child: Row(
                  children: [
                    IconButton(
                      iconSize: 30,
                      icon: const Icon(
                        Icons.pause_circle,
                        color: Colors.black54,
                      ),
                      onPressed: () {
                        // 暂停
                        assetPagKey.currentState?.pause();
                      },
                    ),
                    IconButton(
                      iconSize: 30,
                      icon: const Icon(
                        Icons.play_circle,
                        color: Colors.black54,
                      ),
                      onPressed: () {
                        //播放
                        assetPagKey.currentState?.start();
                      },
                    ),
                    IconButton(
                        iconSize: 30,
                        icon: const Icon(
                          Icons.published_with_changes_sharp,
                          color: Colors.black54,
                        ),
                        onPressed: changeAsset),
                    Text(
                      "<= 请点击控制动画(可切换)",
                      style: TextStyle(fontSize: 14, fontWeight: FontWeight.w500, color: Colors.black54),
                    ),
                  ],
                ),
              ),

              /// TODO: PAGView加载网络资源
              Padding(
                padding: EdgeInsets.only(top: 50, left: 12, bottom: 20),
                child: Text(
                  "PAGView加载网络资源:",
                  style: TextStyle(fontSize: 16, fontWeight: FontWeight.w500, color: Colors.black54),
                ),
              ),
              PAGView.network(
                "https://svipwebwx-30096.sz.gfp.tencent-cloud.com/file1647585475981.pag",
                repeatCount: PAGView.REPEAT_COUNT_LOOP,
                initProgress: 0.25,
                autoPlay: true,
                key: networkPagKey,
              ),
              Padding(
                padding: EdgeInsets.only(left: 12, top: 10),
                child: Row(
                  children: [
                    IconButton(
                      iconSize: 30,
                      icon: const Icon(
                        Icons.pause_circle,
                        color: Colors.black54,
                      ),
                      onPressed: () {
                        // 暂停
                        networkPagKey.currentState?.pause();
                      },
                    ),
                    IconButton(
                      iconSize: 30,
                      icon: const Icon(
                        Icons.play_circle,
                        color: Colors.black54,
                      ),
                      onPressed: () {
                        // 播放
                        networkPagKey.currentState?.start();
                      },
                    ),
                    Text(
                      "<= 请点击控制动画",
                      style: TextStyle(fontSize: 14, fontWeight: FontWeight.w500, color: Colors.black54),
                    ),
                  ],
                ),
              ),

              /// TODO: PAGView加载二进制资源
              Padding(
                padding: EdgeInsets.only(top: 50, left: 12, bottom: 20),
                child: Text(
                  "PAGView加载二进制资源:",
                  style: TextStyle(fontSize: 16, fontWeight: FontWeight.w500, color: Colors.black54),
                ),
              ),
              Visibility(
                  visible: bytesData?.isNotEmpty == true,
                  child: PAGView.bytes(
                    bytesData,
                    repeatCount: PAGView.REPEAT_COUNT_LOOP,
                    initProgress: 0.25,
                    autoPlay: true,
                    key: bytesPagKey,
                  )),
              Padding(
                padding: EdgeInsets.only(left: 12, top: 10),
                child: Row(
                  children: [
                    IconButton(
                      iconSize: 30,
                      icon: const Icon(
                        Icons.pause_circle,
                        color: Colors.black54,
                      ),
                      onPressed: () {
                        // 暂停
                        bytesPagKey.currentState?.pause();
                      },
                    ),
                    IconButton(
                      iconSize: 30,
                      icon: const Icon(
                        Icons.play_circle,
                        color: Colors.black54,
                      ),
                      onPressed: () {
                        // 播放
                        bytesPagKey.currentState?.start();
                      },
                    ),
                    Text(
                      "<= 请点击控制动画",
                      style: TextStyle(fontSize: 14, fontWeight: FontWeight.w500, color: Colors.black54),
                    ),
                  ],
                ),
              ),


              /// TODO: PAGView加载二进制资源
              Padding(
                padding: EdgeInsets.only(top: 20, left: 12, bottom: 20),
                child: Text(
                  "PAGView加载失败的默认占位图:",
                  style: TextStyle(fontSize: 16, fontWeight: FontWeight.w500, color: Colors.black54),
                ),
              ),
              SizedBox(
                width: 100,
                height: 100,
                child: PAGView.asset(
                  _assetError,
                  repeatCount: PAGView.REPEAT_COUNT_LOOP,
                  initProgress: 0.25,
                  autoPlay: true,
                  defaultBuilder: (context){
                    return Container(
                      color: Colors.grey,
                      alignment: Alignment.center,
                      margin: EdgeInsets.all(16),
                      child: Text("load fail"),
                    );
                  },
                ),
              ),
            ],
          ),
        ));
  }
}
    

期待flutter上的PAG插件的更丰富的功能,暂时功能还不太全。

四、小结

flutter开发实战-flutter播放PAG动画

学习记录,每天不停进步。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1689792.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【小tips】当机器里面有多个版本的gcc时,该如何切换当前的gcc版本?

背景切换gcc版本 背景 有时候因为项目需求&#xff0c;可能不同的项目需要不同的gcc版本&#xff0c;所以机器上会安装多个版本的gcc&#xff0c;那我们如何切换到想要使用的版本&#xff1f; 切换gcc版本 比如我的机器上有两个版本的gcc&#xff1a; 我当前的版本是gcc-4…

【C++提高编程-03】----C++之STL常用容器基础实战

&#x1f3a9; 欢迎来到技术探索的奇幻世界&#x1f468;‍&#x1f4bb; &#x1f4dc; 个人主页&#xff1a;一伦明悦-CSDN博客 ✍&#x1f3fb; 作者简介&#xff1a; C软件开发、Python机器学习爱好者 &#x1f5e3;️ 互动与支持&#xff1a;&#x1f4ac;评论 &…

智简云携手云器Lakehouse打造一体化大数据平台,释放数据价值

导读 本篇分享的是智简云使用云器Lakehouse升级数据平台的实践总结。 智简云&#xff0c;是一家拥有十余年历史的科技公司&#xff0c;专注于企业服务领域&#xff0c;开发了两款核心产品&#xff1a;基于PASS平台的客户关系管理&#xff08;CRM&#xff09;系统和为中小型用…

加密与解密(第四版)】第二十三章笔记

第二十三章 代码的二次开发 23.1 数据对齐 23.2 增加空间 利用区块空隙&#xff08;注意区块属性&#xff09; 增加区块&#xff08;增加一个块头、增加块头指向的数据段、调整文件映像的尺寸&#xff08;SizeOfImage&#xff09;&#xff09; 23.3 获得函数的调用信息 修…

用Python的PyAutoGUI库控制鼠标滚轮

哈喽&#xff0c;大家好&#xff0c;我是木头左&#xff01; 轻松上手&#xff1a;安装与导入 要开始使用pyautogui库&#xff0c;你需要做的第一件事就是确保它已经被安装在你的Python环境中。你可以通过运行以下命令来安装&#xff1a; pip install pyautogui安装完成后&am…

【Web】CISCN 2024初赛 题解(全)

目录 Simple_php easycms easycms_revenge ezjava mossfern sanic Simple_php 用php -r进行php代码执行 因为ban了引号&#xff0c;考虑hex2bin&#xff0c;将数字转为字符串 php -r eval(hex2bin(16进制)); 注意下面这段报错&#xff0c;因为加不了引号&#xff0c;开…

稳定性大升级!EMCS全球服务网络携手NineData实现数据实时同步

易客满&#xff08;ECMS Express&#xff09;专注于提供全球化的国际物流解决方案和经济快递服务&#xff0c;服务网络覆盖全球主要贸易市场的国际物流公司。ECMS拥有国际快递、国际货代、仓储供应链全球覆盖服务能力。 1. 易客满&#xff08;ECMS&#xff09;数据复制的技术挑…

初始Java篇(JavaSE基础语法)—— 内部类

找往期文章包括但不限于本期文章中不懂的知识点&#xff1a; 个人主页&#xff1a;我要学编程(ಥ_ಥ)-CSDN博客 所属专栏&#xff1a;JavaSE 目录 内部类的概念 内部类的种类 使用举例&#xff1a; 1. 静态内部类&#xff1a; 2. 实例内部类 3. 局部内部类 4. 匿名内部…

跨境电商赛道,云手机到底能不能化繁为简?

当下国内电商背景&#xff1a; 从零售额的数据来看&#xff1a;随着互联网的普及和消费者购物习惯的改变&#xff0c;国内电商市场规模持续扩大。据相关数据显示&#xff0c;网络消费亮点纷呈&#xff0c;一季度全国网上零售额达到了3.3万亿元&#xff0c;同比增长12.4%。这表…

linux 上除了shell、python脚本以外,还有什么脚本语言用得比较多?

在开始前我有一些资料&#xff0c;是我根据网友给的问题精心整理了一份「 Linux的资料从专业入门到高级教程」&#xff0c; 点个关注在评论区回复“888”之后私信回复“888”&#xff0c;全部无偿共享给大家&#xff01;&#xff01;&#xff01;说到在 Linux下的编程&#xf…

TECHNIUM INTERNATIONAL: 利用 AI 和 TECHNIUM 矩阵协议引领区块链创新

在充满活力的加密货币和区块链技术领域&#xff0c;Technium International 以领军者的姿态迅速崛起&#xff0c;跻身科技巨头的顶尖行列。Technium International 成立于 2018 年&#xff0c;总部设于塞席尔&#xff0c;透过人工智慧&#xff08;AI&#xff09;和区块链技术的…

云计算-基础设施和管理机制(Infrastructure and Management Mechanisms)

逻辑网络边界&#xff08;Logical Network Perimeter&#xff09; 逻辑网络边界是软件控制的虚拟网络&#xff0c;它是物理网络的一部分。其主要思想是隔离逻辑网络&#xff0c;防止不希望的访问&#xff0c;同时仍然为合法用户提供访问权限。下图显示了云系统中一个简单的逻辑…

Windws MySQL 8.4 LTS的安装(保姆级教程)

Windws MySQL 8.4 LTS的安装&#xff08;保姆级教程&#xff09; 一、Mysql版本二、Mysql下载三、Mysql安装3.1 Mysql安装3.2 Mysql配置 四、Mysql环境变量配置五、验证Mysql 一、Mysql版本 美国时间 2024 年 4 月 30 日&#xff0c;Oracle正式发布了MySQL数据库8.0.37版本的更…

初步学习pygame,使用pygame搭建简单的窗口效果

在VSCode上使用pygame 第一步&#xff1a;创建 Python 虚拟环境 打开 VSCode 中的 Terminal&#xff08;在菜单栏中选择 View > Terminal&#xff09;使用 cd 命令切换到你的项目文件夹输入以下命令来创建一个新的虚拟环境&#xff1a; python3 -m venv env这将在你的项目…

机械臂与Realsense D435 相机的手眼标定ROS包

本教程主要介绍机械臂与 Realsense D435 相机手眼标定的配置及方法。 系统&#xff1a;Ubuntu 20.0.4 ◼ ROS&#xff1a;Noetic ◼ OpenCV 库&#xff1a;OpenCV 4.2.0 ◼ Realsense D435&#xff1a;librealsense sdk&#xff08;2.50.0&#xff09;、realsense-ros 功能包&…

electron调试自动更新,不触发下载进度解决方案

调试时候删除掉后缀是.blockmap的文件。如果你的代码在改动不大的情况下发布一个新版本。那个安装器可能会根据这个数据自动合成一个包&#xff0c;而不走网络路径。从而不触发下载进度。

初阶数据结构之双向链表详解

目录 一&#xff1a;双向链表的概念 1.什么是双向链表&#xff1f; 2.双向链表的优点 3.双向链表的结构 二&#xff1a;双向链表的实现 1.定义链表结点 2.初始化双向链表 3.添加结点 4.尾插 5.头插 6.打印双向链表 7.查找链表结点 8.在指定结点后插入新结点 9.删…

KMP算法【C++】

KMP算法测试 KMP 算法详解 根据解释写出对应的C代码进行测试&#xff0c;也可以再整理成一个函数 #include <iostream> #include <vector>class KMP { private:std::string m_pat;//被匹配的字符串std::vector<std::vector<int>> m_dp;//状态二维数组…

【iceberg】数据湖与iceberg调研与实战

文章目录 一. 为什么现在要强调数据湖1. 大数据架构发展历史2. Lambda架构与kappa架构3. 数据湖所具备的能力 二. iceberg是数据湖吗1. iceberg的诞生2. iceberg设计之table format从如上iceberg的数据结构可以知道&#xff0c;iceberg在数据查询时&#xff0c;1.查找文件的时间…

三、自定义信号和槽函数(无参和有参)

需求&#xff1a; 下班后&#xff0c;小明说请小红吃好吃的&#xff0c;随便吃&#xff0c;吃啥买啥 无参&#xff1a;小红没有提出吃啥 有参&#xff1a;小红提出自己想吃的东西&#xff0c;吃啥取决于一时兴起&#xff08;emit触发&#xff09; 思路&#xff1a; 1&#xff…