Flutter中ListView.builder调用setState后不更新的问题排查
问题
我在Flutter中编写了_ProjectDrawerState组件,代码如下:
class _ProjectDrawerState extends State<ProjectDrawer> { @override Widget build(BuildContext context) { double height = MediaQuery.of(context).size.height; double width = MediaQuery.of(context).size.width; bool showMore = false; print('ls Length --- ${widget.ls.length}'); void toggleShowMore() { print('Inside toggleshowMore original value --- $showMore'); setState(() { showMore = !showMore; }); print('Inside toggleshowMOre updated value --- $showMore'); } return Scaffold( body: SafeArea( child: Container( margin: EdgeInsets.only( left: 0.04 * width, right: 0.04 * width, top: 0.14 * height, bottom: 0.1 * height), decoration: BoxDecoration( color: const Color(0xffefefef), borderRadius: BorderRadius.circular(0.037 * width), ), child: SingleChildScrollView( child: IntrinsicHeight( child: ResponsiveRowColumnItem( child: Column( mainAxisAlignment: MainAxisAlignment.start, children: [ Container( height: /*showMore ? (widget.ls.length * height * 0.025) :*/ height * 0.25, child: ListView.builder( physics: const AlwaysScrollableScrollPhysics(), itemCount: showMore ? widget.ls.length : 4, itemBuilder: (BuildContext context, int index) { print('ShowMore value inside ListView.builder --- $showMore'); return SingleChildScrollView( child: ListTile( dense: true, title: Row( children: [ SizedBox(width: width * 0.0255), Image.asset('assets/logo.png', width: 24, height: 24), Text( ' ${widget.ls[index]}', textAlign: TextAlign.center, style: const TextStyle( color: Colors.black, fontFamily: 'Roboto', fontSize: 18, letterSpacing: 0, fontWeight: FontWeight.normal, height: 1), ), ], ), ), ); }, ), ), MaterialButton( onPressed: toggleShowMore, child: Row( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ SizedBox( width: width * 0.22, child: const Divider( color: Color(0xffbdbdbd), thickness: 1.5, height: 0.05), ), Text( showMore ? 'See Less' : 'See more', style: const TextStyle( fontFamily: 'Roboto', fontSize: 18, fontWeight: FontWeight.w600, color: Color(0xff000000), ), ), Icon( showMore ? Icons.arrow_drop_up_sharp : Icons.arrow_drop_down_sharp, color: Colors.black, size: 40, ), SizedBox( width: width * 0.2, child: const Divider( color: Color(0xffbdbdbd), thickness: 1.5, height: 0.05), ), ], ), ), ], ), ), ), ), ), ), ); } }
添加打印语句调试后发现,setState内部的showMore已更新为true,但ListView.builder中的showMore值仍未更新,默认仅显示4条,点击按钮后无预期变化,请问这是为什么?
原因及解决方案
- 核心问题:
showMore被定义在build方法内部,每次调用setState都会触发组件重新执行build,此时showMore会被重新赋值为false,导致UI始终读取初始值,无法响应状态变化。 - 修复步骤:
- 将
showMore移至State类的成员变量区域,作为组件的持久化状态:class _ProjectDrawerState extends State<ProjectDrawer> { bool showMore = false; // 定义为成员变量,初始值false @override Widget build(BuildContext context) { double height = MediaQuery.of(context).size.height; double width = MediaQuery.of(context).size.width; // 移除原build内的bool showMore = false; // 剩余代码保持不变 } } - 调整
toggleShowMore方法,直接修改成员变量:void toggleShowMore() { setState(() { showMore = !showMore; }); }
- 将
- 额外优化:原代码中
Container的高度被固定为height * 0.25,即使showMore为true也不会扩展高度,导致显示更多列表项时会被裁剪,建议恢复注释中的高度逻辑:height: showMore ? (widget.ls.length * height * 0.025) : height * 0.25,
内容的提问来源于stack exchange,提问作者Linisha
相关产品推荐
相关产品推荐

