dotlottie_flutter 0.0.6 copy "dotlottie_flutter: ^0.0.6" to clipboard
dotlottie_flutter: ^0.0.6 copied to clipboard

Render dotLottie and Lottie animations in Flutter. Supports playback control, theming and state machines on Android, iOS, macOS and Web.

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:dotlottie_flutter/dotlottie_flutter.dart';
import 'carousel_page.dart';

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

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

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

class _MyAppState extends State<MyApp> {
  DotLottieViewController? _controller;
  List<Map<String, dynamic>>? _stateMachines;
  String? _activeStateMachine;
  List<Map<String, dynamic>>? _themes;
  String? _activeTheme;

  // Animation control states
  bool _isPlaying = false;
  double _currentFrame = 0;
  double _totalFrames = 0;

  BoxFit _selectedFit = BoxFit.contain;

  @override
  void initState() {
    super.initState();
  }

  Future<void> _loadManifest() async {
    if (_controller != null) {
      final manifest = await _controller!.manifest();
      if (manifest != null) {
        // Safely convert the state machines list
        final stateMachinesRaw = manifest['stateMachines'] as List?;
        if (stateMachinesRaw != null) {
          setState(() {
            _stateMachines = stateMachinesRaw.map((sm) {
              // Convert each item to Map<String, dynamic>
              return Map<String, dynamic>.from(sm as Map);
            }).toList();
          });
        }

        // Safely convert the themes list
        final themesRaw = manifest['themes'] as List?;
        if (themesRaw != null) {
          setState(() {
            _themes = themesRaw.map((theme) {
              return Map<String, dynamic>.from(theme as Map);
            }).toList();
          });
        }

        // Get initial theme if set
        final initialTheme = manifest['initialTheme'] as String?;
        if (initialTheme != null) {
          setState(() {
            _activeTheme = initialTheme;
          });
        }
      }

      // Get initial frame counts
      final total = await _controller!.totalFrames();
      final current = await _controller!.currentFrame();
      if (total != null && current != null) {
        setState(() {
          _totalFrames = total > 0 ? total : 100;
          _currentFrame = current;
        });
      }
    }
  }

  Future<void> _loadAndStartStateMachine(String stateMachineId) async {
    if (_controller != null) {
      final result = await _controller!.stateMachineLoad(stateMachineId);
      if (result == true) {
        await _controller!.stateMachineStart();
        setState(() {
          _activeStateMachine = stateMachineId;
        });
        print('State machine "$stateMachineId" loaded and started');
      }
    }
  }

  Future<void> _stopStateMachine() async {
    if (_controller != null && _activeStateMachine != null) {
      await _controller!.stateMachineStop();
      setState(() {
        _activeStateMachine = null;
      });
      print('State machine stopped');
    }
  }

  Future<void> _setTheme(String themeId) async {
    if (_controller != null) {
      await _controller!.setTheme(themeId);
      setState(() {
        _activeTheme = themeId;
      });
      print('Theme "$themeId" applied');
    }
  }

  Future<void> _handleTotalFrames() async {
    if (_controller != null) {
      var totalFrames = await _controller!.totalFrames();
      if (totalFrames != null) {
        setState(() {
          _totalFrames = totalFrames;
        });
      }
    }
  }

  Future<void> _handlePlay() async {
    if (_controller != null) {
      await _controller!.play();
      setState(() {
        _isPlaying = true;
      });
    }
  }

  Future<void> _handlePause() async {
    if (_controller != null) {
      await _controller!.pause();
      setState(() {
        _isPlaying = false;
      });
    }
  }

  Future<void> _handleStop() async {
    if (_controller != null) {
      await _controller!.stop();
      setState(() {
        _isPlaying = false;
        _currentFrame = 0;
      });
    }
  }

  Future<void> _handleSeek(double frame) async {
    if (_controller != null) {
      await _controller!.setFrame(frame);
      setState(() {
        _currentFrame = frame;
      });
    }
  }

  String _formatFrame(double frame) {
    return frame.toInt().toString();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: const Text('DotLottie Flutter Example')),
        body: SingleChildScrollView(
          child: Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                Padding(
                  padding: const EdgeInsets.symmetric(vertical: 12),
                  child: Builder(
                    builder: (ctx) => ElevatedButton.icon(
                      onPressed: () => Navigator.of(ctx).push(
                        MaterialPageRoute(builder: (_) => const CarouselPage()),
                      ),
                      icon: const Icon(Icons.view_carousel),
                      label: const Text('Carousel Example'),
                    ),
                  ),
                ),
                Container(
                  width: 300,
                  height: 300,
                  color: Colors.grey[200],
                  child: DotLottieView(
                    key: ValueKey(_selectedFit),
                    // multitheme
                    // sourceType: 'url',
                    // source:
                    //     'https://lottie.host/a1641002-1aee-4506-89e2-a18210bfc9c7/PSdkPPlzA5.lottie',

                    // radial state machine
                    // sourceType: 'url',
                    // source:
                    //     'https://lottie.host/fe76f0a1-c3f3-4312-ae5f-5235cdb47c72/Gb5D8cAAzi.lottie',
                    sourceType: 'asset',
                    source: 'star-rating.lottie',

                    // sourceType: 'asset',
                    // source: 'test.json',
                    autoplay: true,
                    useOpenGL: true,
                    loop: true,
                    fit: _selectedFit,
                    onViewCreated: (controller) {
                      setState(() {
                        _controller = controller;
                      });
                    },
                    onLoad: () {
                      _loadManifest();
                      _handleTotalFrames();
                      print('🟢 Dart: Animation loaded!');
                    },
                    onLoadError: () {
                      print('🔴 Dart: Animation load error!');
                    },
                    onPlay: () {
                      setState(() => _isPlaying = true);
                      print('🟢 Dart: Animation playing!');
                    },
                    onPause: () {
                      setState(() => _isPlaying = false);
                    },
                    onStop: () {
                      setState(() => _isPlaying = false);
                    },
                    onFrame: (frameNo) {
                      setState(() {
                        _currentFrame = frameNo;
                      });
                    },
                  ),
                ),
                const SizedBox(height: 16),

                // Fit mode selector
                const Text(
                  'BoxFit:',
                  style: TextStyle(fontSize: 14, fontWeight: FontWeight.bold),
                ),
                const SizedBox(height: 8),
                Wrap(
                  spacing: 6,
                  runSpacing: 6,
                  alignment: WrapAlignment.center,
                  children:
                      [
                        BoxFit.contain,
                        BoxFit.cover,
                        BoxFit.fill,
                        BoxFit.fitWidth,
                        BoxFit.fitHeight,
                        BoxFit.none,
                      ].map((fit) {
                        final isSelected = _selectedFit == fit;
                        return FilterChip(
                          label: Text(fit.name),
                          selected: isSelected,
                          onSelected: (_) => setState(() => _selectedFit = fit),
                        );
                      }).toList(),
                ),
                const SizedBox(height: 20),

                // Display active state machine with stop button
                if (_activeStateMachine != null)
                  Container(
                    padding: const EdgeInsets.all(8),
                    decoration: BoxDecoration(
                      color: Colors.green[100],
                      borderRadius: BorderRadius.circular(8),
                    ),
                    child: Row(
                      mainAxisSize: MainAxisSize.min,
                      children: [
                        Text(
                          'Active: $_activeStateMachine',
                          style: const TextStyle(fontWeight: FontWeight.bold),
                        ),
                        const SizedBox(width: 8),
                        ElevatedButton(
                          onPressed: _stopStateMachine,
                          style: ElevatedButton.styleFrom(
                            backgroundColor: Colors.red,
                            foregroundColor: Colors.white,
                            padding: const EdgeInsets.symmetric(
                              horizontal: 12,
                              vertical: 8,
                            ),
                            minimumSize: Size.zero,
                          ),
                          child: const Text('Stop'),
                        ),
                      ],
                    ),
                  ),

                const SizedBox(height: 20),

                // Themes List
                if (_themes != null && _themes!.isNotEmpty) ...[
                  const Text(
                    'Themes:',
                    style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
                  ),
                  const SizedBox(height: 10),
                  Wrap(
                    spacing: 8,
                    runSpacing: 8,
                    alignment: WrapAlignment.center,
                    children: _themes!.map((theme) {
                      final id = theme['id'] as String;
                      final name = theme['name'] as String?;
                      final displayName = name ?? id;
                      final isActive = _activeTheme == id;

                      return ElevatedButton(
                        onPressed: () => _setTheme(id),
                        style: ElevatedButton.styleFrom(
                          backgroundColor: isActive ? Colors.blue : null,
                          foregroundColor: isActive ? Colors.white : null,
                        ),
                        child: Text(displayName),
                      );
                    }).toList(),
                  ),
                  const SizedBox(height: 20),
                ],

                // State Machines List
                if (_stateMachines != null && _stateMachines!.isNotEmpty) ...[
                  const Text(
                    'State Machines:',
                    style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
                  ),
                  const SizedBox(height: 10),
                  Wrap(
                    spacing: 8,
                    runSpacing: 8,
                    alignment: WrapAlignment.center,
                    children: _stateMachines!.map((sm) {
                      final id = sm['id'] as String;
                      final name = sm['name'] as String?;
                      final displayName = name ?? id;
                      final isActive = _activeStateMachine == id;

                      return ElevatedButton(
                        onPressed: () => _loadAndStartStateMachine(id),
                        style: ElevatedButton.styleFrom(
                          backgroundColor: isActive ? Colors.green : null,
                          foregroundColor: isActive ? Colors.white : null,
                        ),
                        child: Text(displayName),
                      );
                    }).toList(),
                  ),
                  const SizedBox(height: 20),
                ] else if (_controller != null) ...[
                  const Text('No state machines found'),
                  const SizedBox(height: 20),
                ],

                // Animation controls - hidden when state machine is active
                if (_activeStateMachine == null && _controller != null) ...[
                  // Scrub bar
                  Padding(
                    padding: const EdgeInsets.symmetric(horizontal: 20),
                    child: Column(
                      children: [
                        Row(
                          mainAxisAlignment: MainAxisAlignment.spaceBetween,
                          children: [
                            Text(
                              _formatFrame(_currentFrame),
                              style: const TextStyle(fontSize: 12),
                            ),
                            Text(
                              _formatFrame(_totalFrames),
                              style: const TextStyle(fontSize: 12),
                            ),
                          ],
                        ),
                        SliderTheme(
                          data: SliderTheme.of(context).copyWith(
                            trackHeight: 3.0,
                            thumbShape: const RoundSliderThumbShape(
                              enabledThumbRadius: 8.0,
                            ),
                            overlayShape: const RoundSliderOverlayShape(
                              overlayRadius: 16.0,
                            ),
                          ),
                          child: Slider(
                            value: _currentFrame.clamp(0, _totalFrames),
                            min: 0,
                            max: _totalFrames,
                            onChanged: (value) {
                              setState(() {
                                _currentFrame = value;
                              });
                            },
                            onChangeEnd: (value) {
                              _handleSeek(value);
                            },
                          ),
                        ),
                      ],
                    ),
                  ),

                  const SizedBox(height: 10),

                  // Playback controls
                  Row(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: [
                      // Stop button
                      IconButton(
                        onPressed: _handleStop,
                        icon: const Icon(Icons.stop),
                        iconSize: 32,
                        tooltip: 'Stop',
                      ),
                      const SizedBox(width: 20),
                      // Play/Pause button
                      IconButton(
                        onPressed: _isPlaying ? _handlePause : _handlePlay,
                        icon: Icon(_isPlaying ? Icons.pause : Icons.play_arrow),
                        iconSize: 40,
                        tooltip: _isPlaying ? 'Pause' : 'Play',
                      ),
                    ],
                  ),
                ],
              ],
            ),
          ),
        ),
      ),
    );
  }
}
8
likes
0
points
8.22k
downloads

Publisher

verified publisherlottiefiles.com

Weekly Downloads

Render dotLottie and Lottie animations in Flutter. Supports playback control, theming and state machines on Android, iOS, macOS and Web.

Homepage
Repository (GitHub)
View/report issues

License

unknown (license)

Dependencies

flutter, flutter_web_plugins, plugin_platform_interface, web

More

Packages that depend on dotlottie_flutter

Packages that implement dotlottie_flutter