Flutter导航动画卡顿求助:HTTP请求提前返回致UI切换干扰
解决Flutter导航动画卡顿:等待动画完成后发起HTTP请求
这个问题我之前也遇到过!核心原因就是页面导航的过渡动画还在执行时,UI突然因为HTTP请求完成而更新,两者抢GPU资源导致卡顿。下面给你一个可靠的解决方案,确保请求只会在导航动画彻底完成后才发起:
思路说明
我们需要把HTTP请求的触发时机从页面构建时,延迟到导航过渡动画完全结束之后。具体实现上,我们可以用StreamController来手动控制数据流,在确认动画完成后再发起请求并将结果注入流中,这样StreamBuilder就只会在合适的时机更新UI。
修改后的NewPage代码
class _NewPageState extends State<NewPage> { late StreamController<Model> _dataController; @override void initState() { super.initState(); _dataController = StreamController<Model>(); // 等待页面首次渲染完成后,监听导航动画状态 WidgetsBinding.instance.addPostFrameCallback((_) { _waitForNavigationAnimationThenFetch(); }); } void _waitForNavigationAnimationThenFetch() { final currentRoute = ModalRoute.of(context); if (currentRoute?.animation != null) { // 监听动画状态,当动画完成时发起请求 currentRoute!.animation!.addStatusListener((status) { if (status == AnimationStatus.completed) { _fetchData(); } }); } else { // 没有过渡动画(比如直接pushReplacement的情况),直接发起请求 _fetchData(); } } void _fetchData() { Repository().getItem(widget.id).listen( (model) => _dataController.add(model), onError: (error) => _dataController.addError(error), ); } @override void dispose() { _dataController.close(); // 记得关闭控制器,避免内存泄漏 super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( body: StreamBuilder( // 改为使用我们自己的控制器流 stream: _dataController.stream, builder: (context, AsyncSnapshot<Model> itemsSnapshot) { if (itemsSnapshot.hasError) { return ErrorWigets(); } // 初始状态(请求未发起)也显示Spinner if (!itemsSnapshot.hasData) { return Spinner(); } return ListView( children: <Widget>[ // 页面内容 ], ); }, ), ); } }
代码解释
- StreamController:用来手动控制数据的发射时机,替代原来直接从Repository获取流的方式,让我们能完全掌控请求发起时间。
- addPostFrameCallback:确保我们在页面首次渲染完成后再去监听动画状态,避免过早获取路由动画导致的空指针问题。
- 动画状态监听:通过
ModalRoute.of(context)获取当前路由的动画,监听其AnimationStatus.completed状态,确认动画彻底结束后再调用_fetchData发起HTTP请求。 - 资源清理:在
dispose方法中关闭StreamController,避免内存泄漏。
这样修改后,不管HTTP请求响应有多快,都会等导航动画完全结束后才更新UI,彻底解决动画卡顿的问题。
内容的提问来源于stack exchange,提问作者Mingkai Zheng
相关产品推荐
相关产品推荐

