Flutter限制帧率以降低电池消耗的实现方法
Flutter 限制应用帧率到指定值(如30FPS)的可行方案
你提到的重写WidgetBindings的scheduleFrame方法确实能实现帧率限制,但属于底层修改,侵入性较强。下面提供两种更简洁、低侵入的方案,适配不同场景:
方案一:全局帧率限制(适用于整个应用)
通过SchedulerBinding的持久帧回调,计算帧间隔来控制下一次帧调度的时机,实现全局帧率锁定。
import 'dart:async'; import 'package:flutter/scheduler.dart'; class FrameRateLimiter { // 目标帧率,可按需修改 static const targetFps = 30; static final _frameInterval = Duration(milliseconds: 1000 ~/ targetFps); static DateTime? _lastFrameTime; static void init() { SchedulerBinding.instance.addPersistentFrameCallback((_) { if (_lastFrameTime == null) { _lastFrameTime = DateTime.now(); return; } final now = DateTime.now(); final elapsed = now.difference(_lastFrameTime!); if (elapsed < _frameInterval) { // 延迟到目标间隔后再调度下一帧 Timer(_frameInterval - elapsed, () { SchedulerBinding.instance.scheduleFrame(); }); // 取消默认的帧调度,避免重复触发 final callbackId = SchedulerBinding.instance.scheduleFrameCallback((_) {}); SchedulerBinding.instance.cancelFrameCallbackWithId(callbackId); } else { _lastFrameTime = now; } }); } } // 在应用启动时初始化 void main() { FrameRateLimiter.init(); runApp(const MyApp()); }
方案二:仅限制动画帧率(适用于局部动画场景)
如果只是应用内的动画需要降低帧率,无需全局修改,可以自定义TickerProvider来控制动画的触发间隔。
import 'package:flutter/scheduler.dart'; import 'dart:async'; class LimitedTickerProvider extends TickerProvider { static const targetFps = 30; final Duration _interval = Duration(milliseconds: 1000 ~/ targetFps); Timer? _timer; final List<Ticker> _tickers = []; @override Ticker createTicker(TickerCallback onTick) { final ticker = Ticker(onTick, debugLabel: 'LimitedFpsTicker'); _tickers.add(ticker); _startTimerIfNeeded(); return ticker; } void _startTimerIfNeeded() { if (_timer == null && _tickers.isNotEmpty) { _timer = Timer.periodic(_interval, (_) { final timestamp = SchedulerBinding.instance.currentFrameTimeStamp; for (final ticker in _tickers) { if (ticker.isActive) ticker.tick(timestamp); } }); } } @override void dispose() { _timer?.cancel(); for (final ticker in _tickers) ticker.dispose(); super.dispose(); } } // 使用示例 class AnimatedDemo extends StatefulWidget { const AnimatedDemo({super.key}); @override State<AnimatedDemo> createState() => _AnimatedDemoState(); } class _AnimatedDemoState extends State<AnimatedDemo> { late AnimationController _controller; late LimitedTickerProvider _limitedTicker; @override void initState() { super.initState(); _limitedTicker = LimitedTickerProvider(); _controller = AnimationController( duration: const Duration(seconds: 2), vsync: _limitedTicker, )..repeat(); } @override void dispose() { _controller.dispose(); _limitedTicker.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return RotationTransition( turns: _controller, child: const FlutterLogo(size: 200), ); } }
方案对比
- 全局方案:对整个应用的渲染生效,适合需要统一降低帧率的场景,但可能会影响系统原生组件的渲染节奏。
- 局部动画方案:仅作用于指定动画,侵入性低,不会干扰应用其他部分的正常渲染。
- 你提到的重写
WidgetBindings方案:虽然有效,但属于框架底层修改,后续Flutter版本更新可能导致兼容性问题,不推荐优先使用。
内容的提问来源于stack exchange,提问作者user3612643
相关产品推荐
相关产品推荐

