instagram_like_animation_button 2.0.0
instagram_like_animation_button: ^2.0.0 copied to clipboard
Fully customizable Instagram Reels double-tap heart animation for Flutter. Fly-to-target, custom builders, gradients, haptic control.
example/lib/main.dart
import 'package:flutter/material.dart';
import 'package:instagram_like_animation_button/instagram_like_animation_button.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Instagram Like Animation Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const MyHomePage(title: 'Insta Like Demo'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final GlobalKey likeKey = GlobalKey();
bool _isLiked = false;
int _likeCount = 0;
TapDownDetails? _tapDetails;
void _handleDoubleTap(TapDownDetails details) {
setState(() => _tapDetails = details);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(widget.title),
),
body: DoubleTapDetector(
onDoubleTap: _handleDoubleTap,
child: Stack(
children: [
// Background
Container(color: Colors.black),
// Target Icon (where the heart flies to)
Align(alignment: Alignment.center, child: _buildTargetIcon()),
// Animation Layer
if (_tapDetails != null)
ReelAnimationLike(
key: ValueKey(_tapDetails),
likeKey: likeKey,
position: _tapDetails!.globalPosition,
config: const LikeAnimationConfig(
hapticType: HapticFeedbackType.light,
),
style: const LikeAnimationStyle(
iconSize: Size(50, 50),
iconColor: ColorRes.likeRed,
),
leftRightPosition: 8,
topBottomPosition: 65,
onLikeCall: () {
if (_isLiked) return;
setState(() {
_isLiked = true;
_likeCount++;
});
},
onCompleteAnimation: () {
setState(() => _tapDetails = null);
},
),
],
),
),
);
}
Widget _buildTargetIcon() {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
InkWell(
key: likeKey,
onTap: () {
setState(() {
_isLiked = !_isLiked;
if (_isLiked) {
_likeCount++;
} else {
_likeCount--;
}
});
},
child: Image.asset(
_isLiked ? AssetRes.icFillHeart : AssetRes.icHeart,
width: 35,
height: 35,
color: _isLiked ? ColorRes.likeRed : ColorRes.whitePure,
package: 'instagram_like_animation_button',
),
),
if (_likeCount > 0)
Text(
_likeCount.toString(),
style: const TextStyle(color: Colors.white),
),
],
),
);
}
}