Flutter动画时长与设定不符:真机速度快5倍的修复方案咨询
解决Flutter动画受系统开发者选项缩放影响的问题
问题根源
Android开发者选项中的「动画时长缩放」「过渡动画缩放」「动画程序时长缩放」会改变Flutter动画的执行速率,因为Flutter默认使用的SystemTicker会响应系统的动画缩放设置,导致你设定的7500ms动画在不同设备上时长不一致。
解决方案1:抵消系统缩放系数
通过MediaQuery获取系统的动画缩放值,手动调整动画时长,确保实际执行时间符合预期。
修改后的完整代码:
import 'package:flutter/material.dart'; class BookmarkAnimation extends StatefulWidget { const BookmarkAnimation({super.key}); @override _BookmarkAnimationState createState() => _BookmarkAnimationState(); } class _BookmarkAnimationState extends State<BookmarkAnimation> with SingleTickerProviderStateMixin { late AnimationController _animationController; late Animation<double> _animation; bool _isBookmarked = false; late double _animationScale; @override void didChangeDependencies() { super.didChangeDependencies(); // 获取系统动画缩放系数(默认值为1,开发者选项调整后会变化) _animationScale = MediaQuery.of(context).animationScale; // 调整动画控制器的时长,抵消缩放影响 _animationController.duration = Duration(milliseconds: (7500 / _animationScale).round()); } @override void initState() { super.initState(); _animationController = AnimationController( vsync: this, // 初始值仅作为占位,后续在didChangeDependencies中更新 duration: const Duration(milliseconds: 7500), ); _animation = Tween(begin: 0.0, end: 1.0).animate(_animationController); } @override void dispose() { _animationController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { // 同样调整AnimatedCrossFade的时长 final crossFadeDuration = Duration(milliseconds: (7500 / _animationScale).round()); return GestureDetector( onTap: () { setState(() => _isBookmarked = !_isBookmarked); _animationController.isCompleted ? _animationController.reverse() : _animationController.forward(); }, child: RotationTransition( turns: _animation, child: AnimatedCrossFade( firstChild: const Icon(Icons.bookmark_border), secondChild: const Icon(Icons.bookmark), crossFadeState: _isBookmarked ? CrossFadeState.showSecond : CrossFadeState.showFirst, duration: crossFadeDuration, ), ), ); } }
解决方案2:使用不受系统缩放影响的Ticker
如果需要完全脱离系统缩放控制,可自定义一个不响应系统动画设置的TickerProvider:
// 自定义不受系统缩放影响的TickerProvider class UnscaledTickerProvider implements TickerProvider { const UnscaledTickerProvider(); @override Ticker createTicker(TickerCallback onTick) { return Ticker(onTick, debugLabel: 'UnscaledTicker')..stop(); } }
然后修改AnimationController的初始化代码:
@override void initState() { super.initState(); _animationController = AnimationController( vsync: const UnscaledTickerProvider(), // 使用自定义TickerProvider duration: const Duration(milliseconds: 7500), ); _animation = Tween(begin: 0.0, end: 1.0).animate(_animationController); }
注意:使用此方法时需确保
Ticker被正确dispose,避免内存泄漏。
方案对比
- 方案1:简单易实现,能自动适配系统缩放设置,同时保证动画时长一致,适合绝大多数场景。
- 方案2:完全固定动画速度,不受系统设置影响,适合对动画时长有严格要求的场景。
测试时可在开发者选项中调整动画缩放值,验证动画时长是否符合预期。
内容的提问来源于stack exchange,提问作者Mitul Agrawal
相关产品推荐
相关产品推荐

