You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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始终读取初始值,无法响应状态变化。
  • 修复步骤:
    1. 将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;
          // 剩余代码保持不变
        }
      }
      
    2. 调整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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 04:04:56