I'm developing a Flutter app and I'm looking to incorporate a visually appealing animation similar to the one seen in WhatsApp. I have attached a reference clip.
Specifically, I'm interested in replicating the smooth transition, resizing, and sliding of the icons and name when the message bubble expands or collapses. It would be great if you could provide some code snippets or point me in the right direction for creating this effect.
Thank you in advance for your assistance!
You can do this with the help of an animated container, have a function that returns the animated container when a button is pressed. Here's a sample code for an animated container with a bit of animations that might help you.
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage>
with SingleTickerProviderStateMixin {
int _counter = 0;
bool _isCrossVisible = false;
late AnimationController _animationController;
late Animation<double> _rotationAnimation;
@override
void initState() {
super.initState();
_animationController = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 300),
);
// _rotationAnimation = Tween<double>(
// begin: 0,
// end: 0.5,
// ).animate(_animationController);
}
void _toggleAnimation() {
Future.delayed(Duration(milliseconds: 300), (){
setState(() {
showWidgets = true;
});
});
setState(() {
if(showWidgets) {
showWidgets = false;
}
_isCrossVisible = !_isCrossVisible;
if (_isCrossVisible) {
_animationController.forward();
} else {
_animationController.reverse();
}
});
}
@override
void dispose() {
_animationController.dispose();
super.dispose();
}
int _cIndex = 0;
void _incrementTab(index) {
setState(() {
_cIndex = index;
});
}
bool showWidgets = false;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headlineMedium,
),
],
),
),
bottomNavigationBar: Container(
height: 80,
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
topRight: Radius.circular(40), topLeft: Radius.circular(40)),
boxShadow: [
BoxShadow(color: Colors.black38, spreadRadius: 0, blurRadius: 10),
],
),
child: ClipRRect(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(30.0),
topRight: Radius.circular(30.0),
),
child: BottomNavigationBar(
items: <BottomNavigationBarItem>[
BottomNavigationBarItem(icon: Icon(Icons.favorite), label: ""),
BottomNavigationBarItem(icon: Icon(Icons.favorite), label: "")
],
),
)),
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
floatingActionButton: Positioned(
bottom: 80,
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
AnimatedContainer(
duration: const Duration(milliseconds: 300),
curve: Curves.easeInOut,
width: _isCrossVisible ? 200.0 : 0.0,
height: _isCrossVisible ? 200.0 : 0.0,
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.circular(28.0),
),
child: Container(
margin: EdgeInsets.only(left: 15 ,right: 15),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
showWidgets?Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"Mood chech-in",
style: TextStyle(color: Colors.white),
),
Container(
height: 40,
width: 40,
decoration: BoxDecoration(
color: Colors.blueAccent.withOpacity(0.5),
borderRadius: BorderRadius.circular(15.0),
),
child: Center(child:
Icon(Icons.ac_unit, color: Colors.white,)),
),
],
): Container(),
showWidgets? Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text("Voice note", style: TextStyle(color: Colors.white)),
Container(
height: 40,
width: 40,
decoration: BoxDecoration(
color: Colors.blueAccent.withOpacity(0.5),
borderRadius: BorderRadius.circular(15.0),
),
child: Center(child:
Icon(Icons.waves_sharp, color: Colors.white,)),
),
],
): Container(),
showWidgets?Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text("Add photo", style: TextStyle(color: Colors.white)),
Container(
height: 40,
width: 40,
decoration: BoxDecoration(
color: Colors.blueAccent.withOpacity(0.5),
borderRadius: BorderRadius.circular(15.0),
),
child: Center(child:
Icon(Icons.photo, color: Colors.white,)),
),
],
): Container(),
],
),
),
),
Container(
margin: EdgeInsets.only(bottom: 25),
height: 70,
width: 70,
child: IconButton(
icon: AnimatedBuilder(
animation: _animationController,
builder: (context, child) {
return Transform.rotate(
angle: _animationController.value * 0.5 * 3.1415,
child: child,
);
},
child: Icon(
_isCrossVisible ? Icons.close : Icons.add,
size: 30,
color: Colors.white,
),
),
onPressed: _toggleAnimation,
),
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.circular(28.0),
),
),
],
),
),
);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With