import 'package:flutter/material.dart'; final Color darkBlue = Color.fromARGB(255, 18, 32, 47); void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( theme: ThemeData.dark().copyWith(scaffoldBackgroundColor: darkBlue), debugShowCheckedModeBanner: false, home: Scaffold( body: Center( child: ChatAudioTextBubble("Test message"), ), ), ); } } class ChatAudioTextBubble extends StatefulWidget { final String text; ChatAudioTextBubble(this.text); @override _ChatAudioTextBubbleState createState() => _ChatAudioTextBubbleState(); } class _ChatAudioTextBubbleState extends State<ChatAudioTextBubble> with SingleTickerProviderStateMixin { AnimationController _controller; Widget build(BuildContext context) { return GestureDetector( onDoubleTap: () => print("Plays the audio and starts the animation which takes _controller.value from 0-1"), child: Stack(children: [ Positioned.fill( child: Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(10), color: Color(0xFFE6E6E6)), )), ClipRRect( borderRadius: BorderRadius.only( topRight: Radius.circular(10.0), bottomRight: Radius.circular(10.0), ), child: Positioned.fill( child: FractionallySizedBox( alignment: Alignment.centerLeft, heightFactor: 1, widthFactor: _controller == null ? 0 : _controller.value, child: Container( decoration: BoxDecoration( shape: BoxShape.rectangle, color: Colors.blue.withOpacity(0.3), borderRadius: BorderRadius.only( topLeft: Radius.circular(10.0), topRight: Radius.zero, bottomLeft: Radius.circular(10.0), bottomRight: Radius.zero, ), ), ), ))), Container( constraints: BoxConstraints( minWidth: 40, maxWidth: MediaQuery.of(context).size.width * 0.70), child: _buildTextChild()) ])); } Widget _buildTextChild() { final color = Colors.black; return Padding( padding: EdgeInsets.fromLTRB(16, 8, 16, 8), child: Text(widget.text, style: TextStyle(color: color, fontSize: 18))); } }