Flutter滚动监听触发函数过于频繁,如何避免Widget频繁重建?
如何避免滚动监听导致底部导航栏频繁重建?
问题描述
为底部导航栏实现滚动监听控制显示隐藏,功能正常但快速滚动时,满足条件的情况下函数会触发50次以上,导致Widget频繁重建。相关定义:
updateBottomBar:触发父Widget setState的回调函数bottomBarVisible:控制底部导航栏显示隐藏的变量
当前实现代码:
@override void initState() { scrollController.addListener(() { //listener if (scrollController.position.userScrollDirection == ScrollDirection.reverse && widget.bottomBarVisible == true) { print("it is hide"); widget.updateBottomBar(false); } else if (scrollController.position.userScrollDirection == ScrollDirection.forward && widget.bottomBarVisible == false) { print("it is show"); widget.updateBottomBar(true); } }); }
解决方案
1. 本地状态锁,避免重复触发
在当前Widget中维护本地状态标记,只有当本地状态与目标状态不一致时才触发回调,彻底避免重复执行:
bool _localBottomBarVisible = true; @override void initState() { _localBottomBarVisible = widget.bottomBarVisible; scrollController.addListener(() { final scrollDirection = scrollController.position.userScrollDirection; if (scrollDirection == ScrollDirection.reverse && _localBottomBarVisible) { print("it is hide"); _localBottomBarVisible = false; widget.updateBottomBar(false); } else if (scrollDirection == ScrollDirection.forward && !_localBottomBarVisible) { print("it is show"); _localBottomBarVisible = true; widget.updateBottomBar(true); } }); super.initState(); } // 同步父组件传来的状态变化 @override void didUpdateWidget(covariant YourWidget oldWidget) { super.didUpdateWidget(oldWidget); if (oldWidget.bottomBarVisible != widget.bottomBarVisible) { _localBottomBarVisible = widget.bottomBarVisible; } }
2. 节流控制执行频率
通过定时器限制回调的执行间隔,比如150ms内只执行一次,减少高频触发:
Timer? _throttleTimer; const _throttleInterval = Duration(milliseconds: 150); @override void initState() { scrollController.addListener(() { if (_throttleTimer?.isActive ?? false) return; _throttleTimer = Timer(_throttleInterval, () { final scrollDirection = scrollController.position.userScrollDirection; if (scrollDirection == ScrollDirection.reverse && widget.bottomBarVisible) { print("it is hide"); widget.updateBottomBar(false); } else if (scrollDirection == ScrollDirection.forward && !widget.bottomBarVisible) { print("it is show"); widget.updateBottomBar(true); } _throttleTimer = null; }); }); super.initState(); } @override void dispose() { _throttleTimer?.cancel(); scrollController.dispose(); super.dispose(); }
3. 基于滚动位置判断趋势
对比上一次滚动位置判断滚动方向,相比直接监听userScrollDirection能减少触发次数:
double _lastScrollPos = 0; @override void initState() { _lastScrollPos = scrollController.position.pixels; scrollController.addListener(() { final currentPos = scrollController.position.pixels; final isScrollDown = currentPos > _lastScrollPos; if (isScrollDown && widget.bottomBarVisible) { print("it is hide"); widget.updateBottomBar(false); } else if (!isScrollDown && !widget.bottomBarVisible) { print("it is show"); widget.updateBottomBar(true); } _lastScrollPos = currentPos; }); super.initState(); }
内容的提问来源于stack exchange,提问作者Jack Noob
相关产品推荐
相关产品推荐

