flutter_svga_easyplayer

A Flutter package for parsing and rendering SVGA animations efficiently with powerful EasyPlayer features.
SVGA is a lightweight and powerful animation format used for dynamic UI effects in mobile applications.


๐Ÿš€ Features

โœ”๏ธ Parse and render SVGA animations in Flutter.
โœ”๏ธ Load SVGA files from assets and network URLs.
โšก Silent background precaching โ€” hand a list of URLs at startup (or any screen), they get warmed into the cache, and later playback is instant. โœ”๏ธ Intelligent caching system for faster loading and reduced network usage.
โœ”๏ธ Per-widget cache control: Enable/disable caching and auto-cleanup per player.
โœ”๏ธ Playback control modes: infinite loop, play once, or repeat N times with completion callbacks.
โœ”๏ธ Audio Control: Mute/Unmute audio support.
โœ”๏ธ Supports custom dynamic elements (text, images, animations).
โœ”๏ธ Optimized playback performance with animation controllers.
โœ”๏ธ Integrated audio playback within SVGA animations.
โœ”๏ธ Works on Android & iOS (Web & Desktop support coming soon).
โœ”๏ธ Easy loop, stop, and seek functions.


๐Ÿ“Œ Installation

Add flutter_svga_easyplayer to your pubspec.yaml:

dependencies:
  flutter_svga_easyplayer: ^0.0.6

Then, install dependencies:

flutter pub get

๐ŸŽฌ Basic Usage

โœ… Playing an SVGA Animation from Assets

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

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text("Flutter SVGA Example")),
        body: Center(
          child: SVGAEasyPlayer(
            assetsName: "assets/sample_with_audio.svga",
            fit: BoxFit.contain,
          ),
        ),
      ),
    );
  }
}

๐ŸŒ Playing SVGA from a Network URL

SVGAEasyPlayer(
  resUrl: "https://example.com/sample.svga",
  fit: BoxFit.cover,
);

๐ŸŽฎ Playback Control Modes (NEW!)

SVGAEasyPlayer now supports three powerful playback modes:

โœ… Infinite Loop (Default)

SVGAEasyPlayer(
  assetsName: "assets/loading.svga",
  // loops: null (default) - plays infinitely
)

โœ… Play Once

SVGAEasyPlayer(
  assetsName: "assets/splash.svga",
  loops: 0, // Play once then stop
  onFinished: () {
    print("Animation completed!");
    // Navigate to next screen, etc.
  },
)

โœ… Repeat N Times

SVGAEasyPlayer(
  assetsName: "assets/celebration.svga",
  loops: 3, // Play 4 times total (1 + 3 repeats)
  onFinished: () {
    print("All repetitions completed!");
  },
)

๐Ÿ“– Read the full Playback Modes Guide for detailed examples and use cases.


๐Ÿ”Š Audio Control (NEW!)

Control audio playback directly from the widget:

โœ… Mute Audio

SVGAEasyPlayer(
  assetsName: "assets/animation_with_audio.svga",
  isMute: true, // Mutes the audio
)

โšก Silent Background Precaching (NEW in 0.0.6!)

Pass a list of URLs (or asset paths) and the package silently downloads and caches them in the background. Later, when a SVGAEasyPlayer is rendered with the same URL, it plays instantly from the local cache โ€” no network round-trip, no loading flash.

The parser already reads from the same cache on playback, so there is nothing extra to wire up at the widget side.

โœ… At app startup (inside main())

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

void main() {
  WidgetsFlutterBinding.ensureInitialized();

  // Fire-and-forget: warms the cache silently in the background.
  SVGAPrecacheManager.shared.precache(
    const [
      'https://cdn.example.com/a.svga',
      'https://cdn.example.com/b.svga',
      'https://cdn.example.com/c.svga',
    ],
    delay: const Duration(seconds: 1),   // optional: wait for startup to settle
    concurrency: 3,                       // optional: max parallel downloads
    timeout: const Duration(seconds: 15), // optional: per-URL timeout
  );

  runApp(const MyApp());
}

โœ… Anywhere else (any screen, any time)

You are not limited to main(). Trigger precache from initState, a button tap, after login, or whenever your app decides it needs to warm the cache:

class HomeScreen extends StatefulWidget {
  const HomeScreen({super.key});
  @override
  State<HomeScreen> createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  @override
  void initState() {
    super.initState();

    // Fire-and-forget: warms the cache for animations this screen will use.
    SVGAPrecacheManager.shared.precache(const [
      'https://cdn.example.com/home_hero.svga',
      'https://cdn.example.com/home_badge.svga',
    ]);
  }

  @override
  Widget build(BuildContext context) {
    // Instant playback the first time it shows โ€” pre-cached above.
    return const SVGAEasyPlayer(
      resUrl: 'https://cdn.example.com/home_hero.svga',
    );
  }
}

โœ… With progress reporting & result

final result = await SVGAPrecacheManager.shared.precache(
  urls,
  onProgress: (done, total, url, ok) {
    debugPrint('[$done/$total] ${ok ? "OK" : "FAIL"}  $url');
  },
);

debugPrint('precache result: $result');
// SVGAPrecacheResult(total: 6, completed: 6, hits: 2, fetched: 4, failed: 0, cancelled: false)

โœ… From bundled assets

SVGAPrecacheManager.shared.precacheAssets(const [
  'assets/intro.svga',
  'assets/celebration.svga',
]);

โœ… Cancel an in-flight batch

SVGAPrecacheManager.shared.cancel();

๐Ÿง  Why itโ€™s smart

  • โœ… Skip-if-cached โ€” URLs already in the cache are detected and skipped without any network I/O. Safe to call on every app launch.
  • โœ… Deduplicated โ€” if two batches request the same URL at the same time, only one download happens.
  • โœ… Fails gracefully โ€” network errors, asset misses, timeouts or disk errors are swallowed silently; one bad URL never blocks the rest.
  • โœ… Honours global settings โ€” respects SVGACache.shared's enable flag, maxCacheSize, and maxAge.
  • โœ… Cache key parity โ€” uses the exact same cache keys as the parser, so SVGAEasyPlayer(resUrl: url) automatically hits it.

๐Ÿ”Ž API at a glance

Call What it does
SVGAPrecacheManager.shared.precache(urls, ...) Warm the cache with a list of network URLs.
SVGAPrecacheManager.shared.precacheAssets(paths, ...) Warm the cache with a list of bundled asset paths.
SVGAPrecacheManager.shared.cancel() Stop picking up new items from in-flight batches.
SVGAPrecacheManager.shared.isRunning true while any batch is still running.
SVGACache.shared.contains(source) Cheap async check whether a valid cache entry exists.

๐Ÿ’พ Cache Control in EasyPlayer (NEW!)

Control caching behavior on a per-widget basis:

โœ… With Cache (Default - Faster)

SVGAEasyPlayer(
  assetsName: "assets/animation.svga",
  useCache: true, // default - uses cache for fast loading
)

โœ… Without Cache (Always Fresh)

SVGAEasyPlayer(
  resUrl: "https://api.example.com/dynamic.svga",
  useCache: false, // bypass cache, always load fresh
)

โœ… Auto-Cleanup on Dispose

SVGAEasyPlayer(
  assetsName: "assets/one-time.svga",
  clearCacheOnDispose: true, // removes from cache when disposed
  loops: 0,
  onFinished: () => Navigator.pop(),
)

๐Ÿ“– Read the Cache Control Guide for advanced cache management strategies.


๐ŸŽญ Advanced Usage: Using SVGAAnimationController

โœ… Controlling Animation Playback

class MySVGAWidget extends StatefulWidget {
  @override
  _MySVGAWidgetState createState() => _MySVGAWidgetState();
}

class _MySVGAWidgetState extends State<MySVGAWidget>
    with SingleTickerProviderStateMixin {
  late SVGAAnimationController _controller;

  @override
  void initState() {
    super.initState();
    _controller = SVGAAnimationController(vsync: this);
    // Mute audio if needed
    _controller.isMute = true;

    SVGAParser.shared.decodeFromAssets("assets/sample.svga").then((video) {
      _controller.videoItem = video;
      _controller.repeat();
    });
  }

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

  @override
  Widget build(BuildContext context) {
    return SVGAImage(_controller);
  }
}

๐ŸŽจ Customization & Dynamic Elements

โœ… Adding Dynamic Text

controller.videoItem!.dynamicItem.setText(
  TextPainter(
    text: TextSpan(
      text: "Hello SVGA!",
      style: TextStyle(color: Colors.red, fontSize: 18),
    ),
    textDirection: TextDirection.ltr,
  ),
  "text_layer",
);

โœ… Replacing an Image Dynamically

controller.videoItem!.dynamicItem.setImageWithUrl(
  "https://example.com/new_image.png",
  "image_layer",
);

โœ… Hiding a Layer

controller.videoItem!.dynamicItem.setHidden(true, "layer_to_hide");

๐Ÿ—„๏ธ Caching (New!)

Automatic performance optimization with zero breaking changes:

// Caching works automatically - no code changes needed!
final animation = await SVGAParser.shared.decodeFromURL(
  "https://example.com/animation.svga"
);

// Optional: Configure cache settings
SVGACache.shared.setMaxCacheSize(50 * 1024 * 1024); // 50MB
SVGACache.shared.setMaxAge(const Duration(days: 3)); // 3 days

// Optional: Manage cache
await SVGACache.shared.clear(); // Clear all cache
final stats = await SVGACache.shared.getStats(); // Get cache info

๐Ÿ“‹ See CACHE.md for complete caching documentation and examples.


๐ŸŽฏ Playback Controls

controller.forward();  // Play once
controller.repeat();   // Loop playback
controller.stop();     // Stop animation
controller.value = 0;  // Reset to first frame

๐Ÿ›  Common Issues & Solutions

โŒ Black Screen when Loading SVGA

โœ… Solution: Ensure your svga files are correctly placed inside assets/ and registered in pubspec.yaml.

flutter:
  assets:
    - assets/sample.svga

โŒ SVGA Not Loading from Network

โœ… Solution: Ensure the SVGA file is accessible via HTTPS. Test the URL in a browser.

SVGAEasyPlayer(
  resUrl: "https://example.com/sample.svga",
  fit: BoxFit.cover,
);

โŒ Animation Freezes or Doesn't Play

โœ… Solution: Use setState after loading SVGA to rebuild the widget.

setState(() {
  _controller.videoItem = video;
});

๐Ÿ“ฑ Supported Platforms

Platform Supported Audio Support
โœ… Android โœ”๏ธ Yes โœ”๏ธ Yes
โœ… iOS โœ”๏ธ Yes โœ”๏ธ Yes
โœ… Linux โœ”๏ธ Yes โœ”๏ธ Yes
โœ… Web โœ”๏ธ Yes โŒ No
โœ… macOS โœ”๏ธ Yes โœ”๏ธ Yes
โœ… Desktop โœ”๏ธ Yes โœ”๏ธ Yes

๐Ÿ”„ Changelog

See the latest changes in CHANGELOG.md.


๐Ÿ“œ License

This package is licensed under the MIT License. See LICENSE for details.


๐Ÿค Contributing

  • If you find a bug, report it here.
  • Pull requests are welcome! See CONTRIBUTING.md for guidelines.

๐Ÿ‘จโ€๐Ÿ’ป Authors & Contributors

๐Ÿ— Core Author

  • zamansheikh โ€” Lead Developer, Maintainer, and Flutter Integration Engineer.

๐Ÿค Contributors

Special thanks to the amazing contributors who improved flutter_svga:

Contributor Contribution GitHub
wonderkidshihab Fixed repeated music playback bug (#3) ๐Ÿงฉ

Want to contribute? Read CONTRIBUTING.md and submit your PR โ€” weโ€™d love your help!


๐Ÿš€ Enjoy using SVGA animations in your Flutter app! ๐Ÿš€