lottie_pro 0.1.0
lottie_pro: ^0.1.0 copied to clipboard
Enhanced Lottie animations with custom controls and interactions. Supports all 6 platforms with WASM compatibility.
import 'package:flutter/material.dart';
import 'package:lottie_pro/lottie_pro.dart';
void main() {
runApp(const LottieProExampleApp());
}
class LottieProExampleApp extends StatelessWidget {
const LottieProExampleApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'LottiePro Example',
theme: ThemeData(
primarySwatch: Colors.blue,
useMaterial3: true,
),
home: const LottieProExamplePage(),
);
}
}
class LottieProExamplePage extends StatefulWidget {
const LottieProExamplePage({super.key});
@override
State<LottieProExamplePage> createState() => _LottieProExamplePageState();
}
class _LottieProExamplePageState extends State<LottieProExamplePage> {
late LottieProController controller;
late LottieProAnimation animation;
double currentSpeed = 1.0;
double currentFrame = 0.0;
String interactionStatus = 'No interaction';
int selectedSequenceIndex = 0;
@override
void initState() {
super.initState();
controller = LottieProController();
animation = LottieProAnimation(controller: controller);
// Create custom animation sequences
_setupSequences();
// Listen to frame changes and events
controller.events.listen((event) {
if (event == LottieProEvent.frameChanged) {
setState(() {
currentFrame = controller.currentFrame;
});
}
});
// Listen to sequence events
animation.sequenceEvents.listen((event) {
setState(() {
interactionStatus = 'Sequence: ${event.sequence.name} - ${event.type.name}';
});
});
}
void _setupSequences() {
// Create sequences list
final sequences = <AnimationSequence>[
// Sequence 1: Play and reverse
AnimationSequence.playAndReverse(
name: 'Bounce',
speed: 1.5,
waitTime: const Duration(milliseconds: 500),
),
// Sequence 2: Fast play
AnimationSequence.play(
name: 'Fast Play',
speed: 2.0,
loop: false,
),
// Sequence 3: Slow motion
AnimationSequence.play(
name: 'Slow Motion',
speed: 0.5,
loop: false,
),
];
// Add sequences one by one
for (final sequence in sequences) {
animation.addSequence(sequence);
}
}
List<LottieProInteraction> _buildInteractions() {
return [
// Touch interaction - tap to play
TouchInteraction(
interactionArea: const Rect.fromLTWH(0, 0, 300, 300),
onTouch: (controller, position) {
setState(() {
interactionStatus = 'Tapped at: (${position.dx.toStringAsFixed(1)}, ${position.dy.toStringAsFixed(1)})';
});
controller.play();
},
),
// Hover interaction - speed up on hover
HoverInteraction(
interactionArea: const Rect.fromLTWH(0, 0, 300, 300),
onHoverEnter: (controller, position) {
setState(() {
interactionStatus = 'Hovering - Speed increased!';
});
controller.setSpeed(2.0);
},
onHoverExit: (controller, position) {
setState(() {
interactionStatus = 'Hover ended - Normal speed';
});
controller.setSpeed(1.0);
},
),
// Drag interaction - control animation with drag
DragInteraction(
interactionArea: const Rect.fromLTWH(0, 0, 300, 300),
onDragStart: (controller, position) {
setState(() {
interactionStatus = 'Drag started';
});
},
onDragUpdate: (controller, position, delta) {
// Map drag delta to frame changes
final frameDelta = delta.dx * 0.1;
final newFrame = (controller.currentFrame + frameDelta)
.clamp(0.0, controller.totalFrames.toDouble());
controller.goToFrame(newFrame.toInt());
setState(() {
interactionStatus = 'Dragging - Frame: ${newFrame.toStringAsFixed(1)}';
});
},
onDragEnd: (controller, position, velocity) {
setState(() {
interactionStatus = 'Drag ended';
});
},
),
// Scale interaction - pinch to zoom speed
ScaleInteraction(
interactionArea: const Rect.fromLTWH(0, 0, 300, 300),
onScale: (controller, scale, focalPoint) {
// Map scale to speed (1.0 to 3.0)
final newSpeed = (scale * 1.5).clamp(0.5, 3.0);
controller.setSpeed(newSpeed);
setState(() {
interactionStatus = 'Pinch scale: ${scale.toStringAsFixed(2)}x - Speed: ${newSpeed.toStringAsFixed(1)}x';
currentSpeed = newSpeed;
});
},
),
];
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('LottiePro - All Features Demo'),
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
),
body: SingleChildScrollView(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
// Animation display area with interactions
Container(
width: 300,
height: 300,
decoration: BoxDecoration(
border: Border.all(color: Colors.blue, width: 2),
borderRadius: BorderRadius.circular(8),
),
child: ClipRRect(
borderRadius: BorderRadius.circular(8),
child: LottiePro.asset(
'assets/animations/example.json',
controller: controller,
width: 300,
height: 300,
repeat: true,
interactions: _buildInteractions(),
allowCustomInteractions: true, // Set to false for interactive Lottie files
onLoaded: () {
debugPrint('Animation loaded successfully');
setState(() {
interactionStatus = 'Animation loaded - Try interactions!';
});
},
onComplete: () {
debugPrint('Animation completed');
},
onFrameChanged: (frame) {
setState(() {
currentFrame = frame;
});
},
),
),
),
const SizedBox(height: 20),
// Interaction status
Card(
color: Colors.blue.shade50,
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Row(
children: [
const Icon(Icons.touch_app, color: Colors.blue),
const SizedBox(width: 8),
Expanded(
child: Text(
interactionStatus,
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
fontWeight: FontWeight.bold,
),
),
),
],
),
),
),
const SizedBox(height: 20),
// Animation info
Card(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
Text(
'Current Frame: ${currentFrame.toStringAsFixed(1)} / ${controller.totalFrames}',
style: Theme.of(context).textTheme.titleMedium,
),
const SizedBox(height: 8),
Text(
'Speed: ${currentSpeed.toStringAsFixed(1)}x',
style: Theme.of(context).textTheme.titleMedium,
),
const SizedBox(height: 8),
Text(
'State: ${controller.state.name}',
style: Theme.of(context).textTheme.titleMedium,
),
],
),
),
),
const SizedBox(height: 20),
// Control buttons
Wrap(
spacing: 8,
runSpacing: 8,
children: [
ElevatedButton.icon(
onPressed: () => controller.play(),
icon: const Icon(Icons.play_arrow),
label: const Text('Play'),
),
ElevatedButton.icon(
onPressed: () => controller.pause(),
icon: const Icon(Icons.pause),
label: const Text('Pause'),
),
ElevatedButton.icon(
onPressed: () => controller.stop(),
icon: const Icon(Icons.stop),
label: const Text('Stop'),
),
ElevatedButton.icon(
onPressed: () => controller.reverse(),
icon: const Icon(Icons.replay),
label: const Text('Reverse'),
),
],
),
const SizedBox(height: 16),
// Speed control
Card(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
const Text('Speed Control'),
const SizedBox(height: 8),
Row(
children: [
const Text('Speed: '),
Expanded(
child: Slider(
value: currentSpeed,
min: 0.1,
max: 3.0,
divisions: 29,
label: '${currentSpeed.toStringAsFixed(1)}x',
onChanged: (value) {
setState(() {
currentSpeed = value;
});
controller.setSpeed(value);
},
),
),
],
),
],
),
),
),
const SizedBox(height: 16),
// Frame navigation
Card(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
const Text('Frame Navigation'),
const SizedBox(height: 8),
Wrap(
spacing: 8,
runSpacing: 8,
children: [
ElevatedButton(
onPressed: () => controller.previousFrame(),
child: const Text('⏮ Previous'),
),
ElevatedButton(
onPressed: () => controller.goToStart(),
child: const Text('⏪ Start'),
),
ElevatedButton(
onPressed: () => controller.goToEnd(),
child: const Text('⏩ End'),
),
ElevatedButton(
onPressed: () => controller.nextFrame(),
child: const Text('Next ⏭'),
),
],
),
],
),
),
),
const SizedBox(height: 16),
// Custom Animation Sequences
Card(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Custom Animation Sequences',
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
Wrap(
spacing: 8,
runSpacing: 8,
children: [
ElevatedButton(
onPressed: () {
selectedSequenceIndex = 0;
animation.playSequence(0);
},
style: ElevatedButton.styleFrom(
backgroundColor: selectedSequenceIndex == 0
? Colors.blue
: null,
),
child: const Text('Bounce'),
),
ElevatedButton(
onPressed: () {
selectedSequenceIndex = 1;
animation.playSequence(1);
},
style: ElevatedButton.styleFrom(
backgroundColor: selectedSequenceIndex == 1
? Colors.blue
: null,
),
child: const Text('Fast Play'),
),
ElevatedButton(
onPressed: () {
selectedSequenceIndex = 2;
animation.playSequence(2);
},
style: ElevatedButton.styleFrom(
backgroundColor: selectedSequenceIndex == 2
? Colors.blue
: null,
),
child: const Text('Slow Motion'),
),
],
),
const SizedBox(height: 8),
ElevatedButton.icon(
onPressed: () => animation.playNextSequence(),
icon: const Icon(Icons.skip_next),
label: const Text('Next Sequence'),
),
],
),
),
),
const SizedBox(height: 16),
// Interaction Instructions
Card(
color: Colors.green.shade50,
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
const Icon(Icons.info, color: Colors.green),
const SizedBox(width: 8),
Text(
'Interactive Features',
style: Theme.of(context).textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.bold,
),
),
],
),
const SizedBox(height: 12),
_buildInstruction('👆 Tap', 'Play animation'),
_buildInstruction('🖱️ Hover', 'Speed up (desktop/web)'),
_buildInstruction('👈👉 Drag', 'Scrub through frames'),
_buildInstruction('🤏 Pinch', 'Control speed (mobile)'),
],
),
),
),
],
),
),
);
}
Widget _buildInstruction(String icon, String text) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 4.0),
child: Row(
children: [
Text(icon, style: const TextStyle(fontSize: 20)),
const SizedBox(width: 8),
Text(text),
],
),
);
}
@override
void dispose() {
controller.dispose();
animation.dispose();
super.dispose();
}
}