Flutter:切换主题亮度时禁用AnimatedContainer的额外动画
如何禁用AnimatedContainer在主题切换时的颜色额外动画
当AnimatedContainer使用依赖于应用主题亮度的颜色(例如Theme.of(context).colorScheme.onBackground)时,切换主题亮度会触发AnimatedContainer以预设的Duration执行颜色过渡动画,但我们希望主题切换时颜色能像普通Container一样瞬间变化,只保留AnimatedContainer在其他属性变化时的动画。
效果对比:
左侧为AnimatedContainer(主题切换时有颜色动画),右侧为普通Container(主题切换时颜色瞬间变化)
问题复现代码
import 'package:flutter/material.dart'; void main() => runApp(const MyApp()); ValueNotifier<ThemeData> _theme = ValueNotifier( ThemeData(brightness: Brightness.dark, backgroundColor: Colors.white), ); class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return ValueListenableBuilder<ThemeData>( valueListenable: _theme, builder: (_, theme, __) => MaterialApp( theme: theme, title: 'Material App', home: _Scaffold(), ), ); } } class _Scaffold extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Material App Bar'), backgroundColor: Theme.of(context).backgroundColor, ), backgroundColor: Colors.red, body: Center( child: Column( children: <Widget>[ Row( children: <Widget>[ AnimatedContainer( curve: Curves.easeInOutCubic, duration: const Duration(milliseconds: 175), color: Theme.of(context).backgroundColor, width: 50.0, height: 50.0, margin: const EdgeInsets.all(10.0), ), Container( color: Theme.of(context).backgroundColor, width: 50.0, height: 50.0, ), ], ), ElevatedButton( onPressed: () { final Brightness newBrightness = _theme.value.brightness == Brightness.dark ? Brightness.light : Brightness.dark; _theme.value = _theme.value.copyWith( brightness: newBrightness, backgroundColor: newBrightness == Brightness.dark ? Colors.white : Colors.black, ); }, child: const Text('switch brightness'), ), ], ), ), ); } }
解决方案1:动态控制AnimatedContainer的Duration
核心思路:在主题切换的瞬间,将AnimatedContainer的duration设为Duration.zero跳过颜色动画,动画结束后恢复原有时长,确保其他属性(如宽高)的正常动画。
修改后的代码:
import 'package:flutter/material.dart'; void main() => runApp(const MyApp()); ValueNotifier<ThemeData> _theme = ValueNotifier( ThemeData(brightness: Brightness.dark, backgroundColor: Colors.white), ); class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return ValueListenableBuilder<ThemeData>( valueListenable: _theme, builder: (_, theme, __) => MaterialApp( theme: theme, title: 'Material App', home: const _Scaffold(), ), ); } } class _Scaffold extends StatefulWidget { const _Scaffold(); @override State<_Scaffold> createState() => _ScaffoldState(); } class _ScaffoldState extends State<_Scaffold> { bool _isSwitchingTheme = false; final Duration _normalDuration = const Duration(milliseconds: 175); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Material App Bar'), backgroundColor: Theme.of(context).backgroundColor, ), backgroundColor: Colors.red, body: Center( child: Column( children: <Widget>[ Row( children: <Widget>[ AnimatedContainer( curve: Curves.easeInOutCubic, duration: _isSwitchingTheme ? Duration.zero : _normalDuration, color: Theme.of(context).backgroundColor, width: 50.0, height: 50.0, margin: const EdgeInsets.all(10.0), onEnd: () { if (_isSwitchingTheme) { setState(() => _isSwitchingTheme = false); } }, ), Container( color: Theme.of(context).backgroundColor, width: 50.0, height: 50.0, ), ], ), ElevatedButton( onPressed: () { setState(() => _isSwitchingTheme = true); final Brightness newBrightness = _theme.value.brightness == Brightness.dark ? Brightness.light : Brightness.dark; _theme.value = _theme.value.copyWith( brightness: newBrightness, backgroundColor: newBrightness == Brightness.dark ? Colors.white : Colors.black, ); }, child: const Text('switch brightness'), ), ], ), ), ); } }
解决方案2:分离动画属性与主题颜色
如果仅需要AnimatedContainer对非主题相关属性(如宽高、margin)执行动画,可以将颜色部分用普通Container包裹,让AnimatedContainer只处理指定属性的动画:
// 示例:仅对width执行动画,颜色随主题瞬间变化 AnimatedContainer( curve: Curves.easeInOutCubic, duration: const Duration(milliseconds: 175), width: _someAnimatedWidth, // 假设这是需要动画的属性 height: 50.0, margin: const EdgeInsets.all(10.0), child: Container( color: Theme.of(context).backgroundColor, width: double.infinity, height: double.infinity, ), )
内容的提问来源于stack exchange,提问作者Kirill
相关产品推荐
相关产品推荐

