dotLottie Flutter Player Examples
Practical examples of using the dotLottie Flutter player, including playback control, state machines, theming, and slots.
dotLottie Flutter Player Examples
Basic Animation with Controls
import 'package:flutter/material.dart';
import 'package:dotlottie_flutter/dotlottie_flutter.dart';
class AnimationControlsPage extends StatefulWidget {
@override
State<AnimationControlsPage> createState() => _AnimationControlsPageState();
}
class _AnimationControlsPageState extends State<AnimationControlsPage> {
DotLottieViewController? _controller;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('dotLottie Controls')),
body: Column(
children: [
DotLottieView(
source: 'https://lottie.host/example/animation.lottie',
sourceType: 'url',
loop: true,
onViewCreated: (c) => setState(() => _controller = c),
onLoad: () => print('Loaded'),
onComplete: () => print('Complete'),
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
IconButton(
icon: const Icon(Icons.play_arrow),
onPressed: () => _controller?.play(),
),
IconButton(
icon: const Icon(Icons.pause),
onPressed: () => _controller?.pause(),
),
IconButton(
icon: const Icon(Icons.stop),
onPressed: () => _controller?.stop(),
),
],
),
ElevatedButton(
onPressed: () => _controller?.setSpeed(2.0),
child: const Text('2x Speed'),
),
ElevatedButton(
onPressed: () => _controller?.setMode('bounce'),
child: const Text('Bounce Mode'),
),
],
),
);
}
}Controlling Fit and Alignment
Use the fit prop to control how the animation is inscribed into its bounds, just like Flutter's Image widget. Changing fit at runtime pushes the new layout to the native player without recreating the view.
import 'package:flutter/material.dart';
import 'package:dotlottie_flutter/dotlottie_flutter.dart';
class FitExamplePage extends StatefulWidget {
@override
State<FitExamplePage> createState() => _FitExamplePageState();
}
class _FitExamplePageState extends State<FitExamplePage> {
DotLottieViewController? _controller;
BoxFit _fit = BoxFit.contain;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Fit Example')),
body: Column(
children: [
// A non-square container makes the BoxFit differences obvious.
Container(
width: 320,
height: 180,
decoration: BoxDecoration(
color: Colors.grey[200],
border: Border.all(color: Colors.blueAccent),
),
child: DotLottieView(
source: 'assets/animation.lottie',
sourceType: 'asset',
autoplay: true,
loop: true,
fit: _fit,
onViewCreated: (c) => _controller = c,
),
),
const SizedBox(height: 16),
Wrap(
spacing: 8,
children: [
BoxFit.contain,
BoxFit.cover,
BoxFit.fill,
BoxFit.fitWidth,
BoxFit.fitHeight,
BoxFit.none,
].map((fit) {
return FilterChip(
label: Text(fit.name),
selected: _fit == fit,
onSelected: (_) => setState(() => _fit = fit),
);
}).toList(),
),
const SizedBox(height: 16),
// Use setLayout to change alignment without changing the fit prop.
ElevatedButton(
onPressed: () => _controller?.setLayout(
BoxFit.contain,
alignment: Alignment.topLeft,
),
child: const Text('Align top-left (contain)'),
),
ElevatedButton(
onPressed: () => _controller?.setLayout(
BoxFit.contain,
alignment: Alignment.center,
),
child: const Text('Reset to center (contain)'),
),
],
),
);
}
}You can also call setLayout() directly on the controller to change both the fit mode and the alignment at any time:
// Pin the animation to the bottom-right corner.
await _controller?.setLayout(
BoxFit.contain,
alignment: Alignment.bottomRight,
);
// Fill the container completely.
await _controller?.setLayout(BoxFit.fill);Applying a Theme
DotLottieView(
source: 'assets/themed_animation.lottie',
sourceType: 'asset',
autoplay: true,
loop: true,
themeId: 'dark-mode',
onViewCreated: (controller) async {
// Switch themes after 3 seconds
await Future.delayed(const Duration(seconds: 3));
await controller.setTheme('light-mode');
},
)Playing a Segment
DotLottieView(
source: 'assets/animation.lottie',
sourceType: 'asset',
autoplay: true,
loop: true,
segment: [10, 60], // Play frames 10 through 60
)Playing a Named Marker
DotLottieView(
source: 'assets/animation.lottie',
sourceType: 'asset',
autoplay: true,
loop: false,
marker: 'intro',
onComplete: () => print('Intro marker finished'),
)Updating Slots Dynamically
DotLottieView(
source: 'assets/branded_animation.lottie',
sourceType: 'asset',
autoplay: true,
loop: true,
onViewCreated: (controller) async {
// Update brand color and headline text via JSON string
await controller.setSlots(
'{"primaryColor": [1.0, 0.0, 0.0, 1.0], "headlineText": {"t": "Hello Flutter!"}}'
);
},
)Using a State Machine
class InteractiveAnimation extends StatefulWidget {
@override
State<InteractiveAnimation> createState() => _InteractiveAnimationState();
}
class _InteractiveAnimationState extends State<InteractiveAnimation> {
DotLottieViewController? _controller;
@override
Widget build(BuildContext context) {
return Column(
children: [
DotLottieView(
source: 'assets/interactive.lottie',
sourceType: 'asset',
stateMachineId: 'buttonFSM',
onViewCreated: (c) => setState(() => _controller = c),
stateMachineOnStateEntered: (state) {
print('Entered state: $state');
},
stateMachineOnTransition: (from, to) {
print('Transition: $from -> $to');
},
),
ElevatedButton(
onPressed: () async {
await _controller?.stateMachineFire('click');
},
child: const Text('Trigger Click'),
),
ElevatedButton(
onPressed: () async {
await _controller?.stateMachineSetBooleanInput('isActive', true);
},
child: const Text('Set isActive = true'),
),
],
);
}
}Multi-Animation File
DotLottieView(
source: 'assets/multi.lottie',
sourceType: 'asset',
animationId: 'scene-2',
autoplay: true,
loop: true,
onViewCreated: (controller) async {
// Switch to another animation after 5 seconds
await Future.delayed(const Duration(seconds: 5));
await controller.loadAnimation('scene-3');
},
)Related Topics
Last updated: August 13, 2026 at 9:17 AMEdit this page