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

Flutter Web移动端ListView多次滚动后部分项消失问题求助

问题分析与解决方案

核心问题原因

你遇到的移动端Web滚动后列表项消失的问题,和ListView.builder的使用方式直接相关:

  1. 当前代码在itemBuilder中给不符合过滤条件的项返回了height:0的空容器,ListView会一直维护这些空占位项。移动端Web的渲染引擎(如Chrome移动端)在处理大量空占位的动态列表时,多次滚动后容易出现布局缓存异常,导致有效项被错误隐藏。
  2. shrinkWrap: true会让ListView每次滚动都重新计算整体高度,频繁的高度计算叠加空占位的干扰,进一步加剧了布局偏移的概率。

具体修复步骤

1. 提前过滤数据,避免空占位项

不要在itemBuilder里判断过滤条件,而是先把符合条件的数据单独筛选出来,再传给ListView构建:

case UserListStateSuccess:
  // 先过滤符合搜索条件的用户列表
  final filteredUsers = viewmodel.userList!.where((user) {
    final circleMatch = viewmodel.searchCircle == circleListForSearch[0] || 
                        user.circle_circle_name == viewmodel.searchCircle;
    final majorMatch = viewmodel.searchMajor == majorListForSearch[0] || 
                       user.major_major_name == viewmodel.searchMajor;
    final nameMatch = viewmodel.searchName.isEmpty || 
                      user.member_user_name.contains(viewmodel.searchName);
    return circleMatch && majorMatch && nameMatch;
  }).toList();

  return filteredUsers.isNotEmpty
      ? ListView.builder(
          shrinkWrap: true, // 如果父容器允许,建议去掉这个属性,改用固定高度或让父容器约束高度
          itemBuilder: (context, index) {
            final user = filteredUsers[index];
            return userListItemContainer(
              userInfo: user,
              onTap: () => viewmodel.selectedItem(viewmodel.userList!.indexOf(user)),
              isSelected: viewmodel.selectedIndex == viewmodel.userList!.indexOf(user),
            );
          },
          itemCount: filteredUsers.length)
      : Center(
          child: Text(
            "사용자가 없습니다",
            style: kTextMainStyle.copyWith(fontSize: kTextTitleSize),
          ),
        );

2. 优化列表项布局,避免嵌套滚动冲突

renderInfoContainer里的横向滚动嵌套在Expanded中,容易导致移动端Web的布局计算混乱,建议简化结构(如果不需要横向滚动,直接用文本截断即可):

Widget renderInfoContainer({
required String info,
bool isSelected = false,
}) {
return Padding(
  padding: EdgeInsets.only(right: kPaddingMiddleSize),
  child: Expanded(
    child: Text(
      info,
      overflow: TextOverflow.ellipsis,
      maxLines: 1,
      style: kTextNormalStyle.copyWith(
        fontSize: kTextMiddleSize,
        color: isSelected ? kBackgroundMainColor : kTextMainColor,
      ),
    ),
  ),
);
}

3. 可选:移除shrinkWrap(如果父容器支持)

如果ListView的父容器有明确的高度约束(比如放在Scaffold的body里),建议去掉shrinkWrap: true,让ListView自动占满可用空间,减少不必要的高度重计算。

修复原理

  • 过滤后列表仅保留有效项,ListView无需维护空占位,布局计算更稳定
  • 简化嵌套滚动结构,避免移动端Web渲染引擎的布局冲突
  • 减少动态高度重计算的频率,降低滚动时的布局异常概率

内容的提问来源于stack exchange,提问作者kim

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 17:33:24