Flutter:点击FAB时实现Chapter文本左滑并同步显示内容的动画
实现方案
完全可以实现,只需要给"Chapter"文本添加平移动画,并和"01"的淡入淡出动画保持同步时长即可。以下是修改后的完整代码:
class _MyHomePageState extends State<MyHomePage> { bool visible = false; // 统一动画时长,确保两个动画同步 final Duration _animationDuration = const Duration(milliseconds: 500); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( backgroundColor: Theme.of(context).colorScheme.inversePrimary, title: const Text('Flutter Demo Home Page'), centerTitle: true, ), body: Center( child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ // 用AnimatedContainer实现"Chapter"的平移动画 AnimatedContainer( duration: _animationDuration, // visible为true时向左移动20像素,可根据需求调整距离 transform: Matrix4.translationValues(visible ? -20 : 0, 0, 0), child: const Text( 'Chapter ', style: TextStyle(fontSize: 22), ), ), Visibility( visible: visible, maintainAnimation: true, maintainState: true, child: AnimatedOpacity( opacity: visible ? 1 : 0, duration: _animationDuration, child: const Text( '01', style: TextStyle(fontSize: 22), ), ), ), ], ), ), floatingActionButton: FloatingActionButton( child: const Icon(Icons.add), onPressed: () { setState(() => visible = !visible); }, ), ); } }
关键说明
- 定义
_animationDuration统一管理动画时长,避免重复写数值,确保"Chapter"的平移动画和"01"的淡入淡出动画完全同步。 - 使用
AnimatedContainer的transform属性实现水平位移:通过Matrix4.translationValues控制X轴方向的移动,visible为true时向左移动20像素(你可以根据需求调整这个数值,比如改成-30让移动距离更大)。 - 点击FAB切换
visible状态时,两个动画会同时触发,时长均为500毫秒。
进阶优化(精准位移)
如果想要"Chapter"移动的距离刚好等于"01"文本的宽度,让动画更自然,可以通过LayoutBuilder动态获取文本宽度:
class _MyHomePageState extends State<MyHomePage> { bool visible = false; final Duration _animationDuration = const Duration(milliseconds: 500); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( backgroundColor: Theme.of(context).colorScheme.inversePrimary, title: const Text('Flutter Demo Home Page'), centerTitle: true, ), body: Center( child: LayoutBuilder( builder: (context, constraints) { // 动态计算"01"文本的实际宽度 final textWidth = (TextPainter( text: const TextSpan(text: '01', style: TextStyle(fontSize: 22)), textScaleFactor: MediaQuery.of(context).textScaleFactor, textDirection: TextDirection.ltr, )..layout()).width; return Row( mainAxisAlignment: MainAxisAlignment.center, children: [ AnimatedContainer( duration: _animationDuration, // 位移距离等于"01"文本的宽度 transform: Matrix4.translationValues(visible ? -textWidth : 0, 0, 0), child: const Text('Chapter ', style: TextStyle(fontSize: 22)), ), Visibility( visible: visible, maintainAnimation: true, maintainState: true, child: AnimatedOpacity( opacity: visible ? 1 : 0, duration: _animationDuration, child: const Text('01', style: TextStyle(fontSize: 22)), ), ), ], ); }, ), ), floatingActionButton: FloatingActionButton( child: const Icon(Icons.add), onPressed: () { setState(() => visible = !visible); }, ), ); } }
内容的提问来源于stack exchange,提问作者Fábio Michel dos Santos
相关产品推荐
相关产品推荐

