Flutter中FutureBuilder内ListView中的AnimatedContainer无法正常工作
解决Flutter Web中MouseRegion悬停无响应的问题
我帮你排查下问题所在:你代码里的核心问题是每个列表项的hover状态没有被正确维护。你在itemBuilder里直接定义了var hover = true;,这是个局部变量——每次setState触发后,ListView.builder会重新构建列表项,这个变量都会被重置回true,而且它也不是组件的状态变量,setState根本没法追踪它的变化,自然悬停时看不到UI更新。
下面给你两种可行的解决方案:
方案一:用StatefulWidget封装单个列表项
把每个列表项做成独立的StatefulWidget,让每个项自己管理自己的hover状态,这样就不会被列表重建影响了。
修改后的代码示例
// 先定义单个仓库项的StatefulWidget class RepoItem extends StatefulWidget { final Repo repo; const RepoItem({Key? key, required this.repo}) : super(key: key); @override State<RepoItem> createState() => _RepoItemState(); } class _RepoItemState extends State<RepoItem> { // 这里把hover作为当前组件的状态变量 bool _hover = false; @override Widget build(BuildContext context) { return MouseRegion( onEnter: (_) { setState(() { _hover = true; }); }, onExit: (_) { setState(() { _hover = false; }); }, child: AnimatedContainer( duration: const Duration(seconds: 1), curve: Curves.bounceIn, height: _hover ? 320 : 300, width: _hover ? 470 : 450, margin: const EdgeInsets.all(5), decoration: BoxDecoration( color: _hover ? Colors.red : Colors.black, border: Border.all(color: Colors.white70), borderRadius: BorderRadius.circular(20), ), padding: const EdgeInsets.all(10), child: // 这里放你原来的子组件,比如显示repo信息的内容 Text(widget.repo.name), // 示例,替换成你的实际内容 ), ); } } // 然后在原来的FutureBuilder里使用这个组件 FutureBuilder<List<Repo>>( future: receberDados, builder: (context, snap) { if (snap.connectionState == ConnectionState.done) { var repos = snap.data; return Container( height: 350, child: ListView.builder( scrollDirection: Axis.horizontal, itemCount: repos!.length, itemBuilder: (context, i) { return RepoItem(repo: repos[i]); }, ), ); } return const CircularProgressIndicator(); }, )
方案二:用ValueNotifier管理状态(无StatefulWidget)
如果不想额外创建StatefulWidget,也可以用ValueNotifier来单独管理每个项的hover状态,配合ValueListenableBuilder来更新UI:
FutureBuilder<List<Repo>>( future: receberDados, builder: (context, snap) { if (snap.connectionState == ConnectionState.done) { var repos = snap.data; return Container( height: 350, child: ListView.builder( scrollDirection: Axis.horizontal, itemCount: repos!.length, itemBuilder: (context, i) { // 每个项创建自己的ValueNotifier final hoverNotifier = ValueNotifier<bool>(false); return MouseRegion( onEnter: (_) => hoverNotifier.value = true, onExit: (_) => hoverNotifier.value = false, child: ValueListenableBuilder<bool>( valueListenable: hoverNotifier, builder: (context, hover, child) { return AnimatedContainer( duration: const Duration(seconds: 1), curve: Curves.bounceIn, height: hover ? 320 : 300, width: hover ? 470 : 450, margin: const EdgeInsets.all(5), decoration: BoxDecoration( color: hover ? Colors.red : Colors.black, border: Border.all(color: Colors.white70), borderRadius: BorderRadius.circular(20), ), padding: const EdgeInsets.all(10), child: child, ); }, child: // 这里放你的子组件,比如Text(repos[i].name) Text(repos[i].name), ), ); }, ), ); } return const CircularProgressIndicator(); }, )
额外注意点
- 你在
initState里定义receberDados的做法是对的,避免了FutureBuilder每次build都重新发起请求,这点很好~ - 测试的时候可以把
duration改短一点(比如Duration(milliseconds: 300)),这样悬停效果会更直观,1秒的动画有点慢哦。
内容的提问来源于stack exchange,提问作者ichin23
相关产品推荐
相关产品推荐

