Flutter VAP2协议支持插件flutter_vap2的使用

Flutter VAP2协议支持插件flutter_vap2的使用

中文文档

Backdrop

透明视频动画是当前较为流行的动画实现方式之一。各大厂商也开源了自己的框架。最终,我们选择了由企鹅电竞开发的VAP(Video Animation Player),它支持Android、iOS和Web,并且提供了方便的封装flutter_vap。它提供了一个工具,可以从帧图像生成带有Alpha通道的视频,这非常棒。

VAP(Video Animation Player)是由企鹅电竞开发的,用于播放酷炫动画。

  • 相比于Webp和Apng动画解决方案,它具有更高的压缩率(更小的素材)和硬件解码(更快的解码速度)
  • 相比于Lottie,它可以实现更复杂的动画效果(如粒子效果)

Preview

Youtube 视频

七牛云视频

APK 下载

Setup

dependencies:
  flutter_vap2: ${last_version}

如何使用

import 'package:flutter_vap2/flutter_vap.dart';

VapViewController vapViewController;

// VapView可以通过外层包Container(),设置宽高来限制弹出视频的宽高
IgnorePointer(
  child: VapView(
    onVapViewCreated: (controller) {
        vapViewController = controller;
    }
  ),
),
  1. 播放本地视频
Future<Map<dynamic, dynamic>> _playFile(String path) async {
  if (path == null) {
    return null;
  }
  var res = await vapViewController.playPath(path);
  if (res["status"] == "failure") {
    showToast(res["errorMsg"]);
  }
  return res;
}
  1. 播放资源文件
Future<Map<dynamic, dynamic>> _playAsset(String asset) async {
  if (asset == null) {
    return null;
  }
  var res = await vapViewController.playAsset(asset);
  if (res["status"] == "failure") {
    showToast(res["errorMsg"]);
  }
  return res;
}
  1. 停止播放
VapController.stop()
  1. 队列播放
_queuePlay() async {
  // 模拟多个地方同时调用播放,使得队列执行播放。
  QueueUtil.get("vapQueue").addTask(() => vapViewController.playPath(downloadPathList[0]));
  QueueUtil.get("vapQueue").addTask(() => vapViewController.playPath(downloadPathList[1]));
}
  1. 取消队列播放
_cancelQueuePlay() {
  QueueUtil.get("vapQueue").cancelTask();
}

示例代码

import 'dart:async';
import 'dart:io';

import 'package:dio/dio.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_vap2/flutter_vap.dart';
import 'package:oktoast/oktoast.dart';
import 'package:path_provider/path_provider.dart';

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

class MyApp extends StatefulWidget {
  [@override](/user/override)
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  List<String> downloadPathList;
  bool isDownload = false;
  VapViewController vapViewController;

  [@override](/user/override)
  void initState() {
    super.initState();
    initDownloadPath();
  }

  Future<void> initDownloadPath() async {
    Directory appDocDir = await getApplicationDocumentsDirectory();
    String rootPath = appDocDir.path;
    downloadPathList = ["$rootPath/vap_demo1.mp4", "$rootPath/vap_demo2.mp4"];
    print("downloadPathList:$downloadPathList");
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return OKToast(
      child: MaterialApp(
        home: Scaffold(
          body: Container(
            width: double.infinity,
            height: double.infinity,
            decoration: BoxDecoration(
              color: Color.fromARGB(255, 140, 41, 43),
              image: DecorationImage(image: AssetImage("static/bg.jpeg")),
            ),
            child: Stack(
              alignment: Alignment.bottomCenter,
              children: [
                Column(
                  mainAxisSize: MainAxisSize.min,
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    CupertinoButton(
                      color: Colors.purple,
                      child: Text("下载视频源${isDownload ? "(✅)" : ""}"),
                      onPressed: _download,
                    ),
                    CupertinoButton(
                      color: Colors.purple,
                      child: Text("File1 播放"),
                      onPressed: () => _playFile(downloadPathList[0]),
                    ),
                    CupertinoButton(
                      color: Colors.purple,
                      child: Text("File2 播放"),
                      onPressed: () => _playFile(downloadPathList[1]),
                    ),
                    CupertinoButton(
                      color: Colors.purple,
                      child: Text("资源播放"),
                      onPressed: () => _playAsset("static/demo.mp4"),
                    ),
                    CupertinoButton(
                      color: Colors.purple,
                      child: Text("停止播放"),
                      onPressed: () => vapViewController?.stop(),
                    ),
                    CupertinoButton(
                      color: Colors.purple,
                      child: Text("队列播放"),
                      onPressed: _queuePlay,
                    ),
                    CupertinoButton(
                      color: Colors.purple,
                      child: Text("取消队列播放"),
                      onPressed: _cancelQueuePlay,
                    ),
                  ],
                ),
                IgnorePointer(
                  // VapView可以通过外层包Container(),设置宽高来限制弹出视频的宽高
                  child: Container(
                    width: 414,
                    height: 736,
                    child: VapView(
                      onVapViewCreated: (controller) {
                        vapViewController = controller;
                      },
                    ),
                  ),
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }

  _download() async {
    await Dio().download("http://file.jinxianyun.com/vap_demo1.mp4", downloadPathList[0]);
    await Dio().download("http://file.jinxianyun.com/vap_demo2.mp4", downloadPathList[1]);
    setState(() {
      isDownload = true;
    });
  }

  Future<Map<dynamic, dynamic>> _playFile(String path) async {
    if (path == null) {
      return null;
    }
    var res = await vapViewController?.playPath(path);
    if (res?["status"] == "failure") {
      showToast(res?["errorMsg"]);
    }
    return res;
  }

  Future<Map<dynamic, dynamic>> _playAsset(String asset) async {
    if (asset == null) {
      return null;
    }
    var res = await vapViewController?.playAsset(asset);
    if (res?["status"] == "failure") {
      showToast(res?["errorMsg"]);
    }
    return res;
  }

  _queuePlay() async {
    // 模拟多个地方同时调用播放,使得队列执行播放。
    QueueUtil.get("vapQueue")
        .addTask(() => vapViewController?.playPath(downloadPathList[0]));
    QueueUtil.get("vapQueue")
        .addTask(() => vapViewController?.playPath(downloadPathList[1]));
  }

  _cancelQueuePlay() {
    QueueUtil.get("vapQueue").cancelTask();
  }
}

更多关于Flutter VAP2协议支持插件flutter_vap2的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter VAP2协议支持插件flutter_vap2的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是一个关于如何在Flutter项目中使用flutter_vap2插件来支持VAP2协议的示例代码。这个插件假设它提供了与VAP2协议进行交互的基本功能。由于具体的插件实现细节和API可能会有所不同,以下代码是一个基于假设的示例,旨在展示如何使用这样的插件。

首先,确保你已经在pubspec.yaml文件中添加了flutter_vap2依赖:

dependencies:
  flutter:
    sdk: flutter
  flutter_vap2: ^x.y.z  # 替换为实际的版本号

然后运行flutter pub get来安装依赖。

接下来,在你的Flutter项目中,你可以按照以下方式使用flutter_vap2插件:

import 'package:flutter/material.dart';
import 'package:flutter_vap2/flutter_vap2.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter VAP2 Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  VAP2Client? _vap2Client;
  String _status = 'Not Connected';

  @override
  void initState() {
    super.initState();
    // 初始化VAP2客户端
    _initVAP2Client();
  }

  void _initVAP2Client() async {
    // 假设VAP2Client需要一个服务器URL和可能的认证信息
    String serverUrl = 'https://your-vap2-server.com';
    String? username = 'your-username';
    String? password = 'your-password';

    _vap2Client = VAP2Client(serverUrl, username, password);

    // 监听连接状态变化
    _vap2Client!.onStatusChanged.listen((status) {
      setState(() {
        _status = status;
      });
    });

    // 尝试连接到VAP2服务器
    try {
      await _vap2Client!.connect();
      setState(() {
        _status = 'Connected';
      });
    } catch (e) {
      print('Failed to connect to VAP2 server: $e');
      setState(() {
        _status = 'Connection Failed';
      });
    }
  }

  void _sendCommand() async {
    if (_vap2Client!.isConnected) {
      // 假设sendCommand是一个发送VAP2命令的方法
      String command = 'your-vap2-command';
      try {
        var response = await _vap2Client!.sendCommand(command);
        print('Response from VAP2 server: $response');
      } catch (e) {
        print('Failed to send command: $e');
      }
    } else {
      print('Not connected to VAP2 server.');
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter VAP2 Demo'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'Status: $_status',
              style: TextStyle(fontSize: 24),
            ),
            SizedBox(height: 20),
            ElevatedButton(
              onPressed: _sendCommand,
              child: Text('Send VAP2 Command'),
            ),
          ],
        ),
      ),
    );
  }

  @override
  void dispose() {
    // 断开VAP2客户端连接
    _vap2Client?.disconnect();
    super.dispose();
  }
}

// 假设的VAP2Client类定义(实际使用时请参考插件文档)
class VAP2Client {
  String _serverUrl;
  String? _username;
  String? _password;
  bool _isConnected = false;
  final _statusController = StreamController<String>();

  Stream<String> get onStatusChanged => _statusController.stream;

  VAP2Client(this._serverUrl, this._username, this._password);

  Future<void> connect() async {
    // 假设的连接逻辑
    // ...
    _isConnected = true;
    _statusController.add('Connected');
  }

  Future<String> sendCommand(String command) async {
    // 假设的发送命令逻辑
    // ...
    return 'Command Sent';
  }

  void disconnect() {
    _isConnected = false;
    _statusController.add('Disconnected');
    _statusController.close();
  }

  bool get isConnected => _isConnected;
}

注意

  1. 上面的VAP2Client类是一个假设的实现,用于展示如何设计该类。实际使用时,你需要参考flutter_vap2插件的文档来了解其API和具体实现。
  2. 在真实的应用中,处理异常、错误和状态管理可能会更加复杂,这里仅展示了基本的连接和命令发送逻辑。
  3. 确保你的VAP2服务器URL、用户名和密码是正确的,并且服务器支持VAP2协议。

希望这个示例代码能帮助你开始在Flutter项目中使用flutter_vap2插件。

回到顶部