我正在开发一个Flutter应用程序,我希望将一个视觉上吸引人的动画类似于WhatsApp中看到的动画。我附上了一个参考剪辑。x1c 0d1x具体来说,我感兴趣的是在消息气泡展开或折叠时复制图标和名称的平滑过渡、调整大小和滑动。如果您能提供一些代码片段或为我指出创建此效果的正确方向,那就太好了。提前感谢您的帮助!
aelbi1ox1#
你可以在动画容器的帮助下做到这一点,有一个函数,当按下按钮时返回动画容器。下面是一个动画容器的示例代码,其中的一些动画可能会对您有所帮助。
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), ), ), ], ), ), ); } }
1条答案
按热度按时间aelbi1ox1#
你可以在动画容器的帮助下做到这一点,有一个函数,当按下按钮时返回动画容器。下面是一个动画容器的示例代码,其中的一些动画可能会对您有所帮助。