Flutter:保持HomeScreen为StatelessWidget实现AppBar同步图标旋转动画
在StatelessWidget中实现AppBar图标按钮的旋转动画
要在保持HomeScreen为StatelessWidget的前提下实现IconButton的旋转动画,可以用ValueNotifier配合ValueListenableBuilder来做,不用把组件改成Stateful。具体实现方式如下:
步骤1:用ValueNotifier管理动画状态
我们用一个ValueNotifier<bool>来标记当前是否正在执行数据库操作,以此控制动画的启停:
final ValueNotifier<bool> _isRefreshing = ValueNotifier(false);
步骤2:替换IconButton为带旋转动画的组件
把原来的IconButton替换成监听状态变化的动画组件,通过RotationTransition实现旋转效果:
ValueListenableBuilder<bool>( valueListenable: _isRefreshing, builder: (context, isRefreshing, child) { final animationController = AnimationController( vsync: Navigator.of(context), duration: const Duration(milliseconds: 500), ); // 根据状态控制动画启停 if (isRefreshing) { animationController.repeat(); } else { animationController.stop(); } return IconButton( onPressed: () async { _isRefreshing.value = true; // 启动动画 try { await DatabaseService().signInAutomatically(); // 执行数据库操作 } finally { _isRefreshing.value = false; // 确保动画停止 } }, tooltip: 'Refresh connection status', icon: RotationTransition( turns: Tween(begin: 0.0, end: 1.0).animate( CurvedAnimation( parent: animationController, curve: Curves.linear, ), ), child: const Icon(Icons.sync, color: Colors.white), ), ); }, )
完整的HomeScreen代码
整合后的完整代码如下:
class HomeScreen extends StatelessWidget { const HomeScreen({super.key}); final ValueNotifier<bool> _isRefreshing = ValueNotifier(false); @override Widget build(BuildContext context) { return DefaultTabController( length: 2, child: SafeArea( child: Scaffold( appBar: AppBar( actions: <Widget>[ ValueListenableBuilder<bool>( valueListenable: _isRefreshing, builder: (context, isRefreshing, child) { final animationController = AnimationController( vsync: Navigator.of(context), duration: const Duration(milliseconds: 500), ); if (isRefreshing) { animationController.repeat(); } else { animationController.stop(); } return IconButton( onPressed: () async { _isRefreshing.value = true; try { await DatabaseService().signInAutomatically(); } finally { _isRefreshing.value = false; } }, tooltip: 'Refresh connection status', icon: RotationTransition( turns: Tween(begin: 0.0, end: 1.0).animate( CurvedAnimation( parent: animationController, curve: Curves.linear, ), ), child: const Icon(Icons.sync, color: Colors.white), ), ); }, ) ], title: Constants.appname, flexibleSpace: Container( decoration: BoxDecoration( gradient: LinearGradient(colors: [ Theme.of(context).colorScheme.primary, Theme.of(context).colorScheme.secondary ], begin: Alignment.topCenter, end: Alignment.bottomCenter), ), ), toolbarHeight: 110, centerTitle: true, automaticallyImplyLeading: false, bottom: const TabBar( indicatorColor: Colors.white, tabs: [ Tab( icon: Icon(Icons.work, color: Colors.white), ), Tab( icon: Icon(Icons.home_work, color: Colors.white), ) ], ), ), body: TabBarView( children: [ Container( alignment: Alignment.center, child: const StampInFromOffice(), ), Container( alignment: Alignment.center, child: const StampInFromHome(), ), ], ), ), ), ); } }
补充说明
ValueNotifier是轻量级状态管理工具,适合这种单一状态的场景,完全不需要将StatelessWidget改为StatefulWidget- 用
try/finally包裹数据库操作,确保无论操作成功或失败,动画都会停止,避免无限旋转 - 动画控制器的
vsync使用Navigator.of(context)获取TickerProvider,无需额外实现接口
内容的提问来源于stack exchange,提问作者RazerMackham
相关产品推荐
相关产品推荐

