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

Flutter:如何为ListView末尾添加阴影且不影响滚动?

Flutter ListView末尾添加阴影且不影响滚动的解决方案

问题场景

我需要给Flutter的ListView末尾(最后一个Widget)添加阴影效果,初始实现代码如下:

return controller.tasksData == null
        ? Center(
            child: SizedBox(
              height: 40,
              width: 40,
              child: CircularProgressIndicator(
                color: AppColor.main_blue,
              ),
            ),
          )
        : controller.PendingTasks.isNotEmpty
            ? Container(
                margin:
                    const EdgeInsets.symmetric(vertical: 20, horizontal: 7),
                child: ListView.builder(
                  physics: const BouncingScrollPhysics(),
                  itemCount: controller.PendingTasks.length,
                  itemBuilder: (context, index) {
                    return Container(
                      margin: const EdgeInsets.only(bottom: 10),
                      child: TaskCard(
                        tasktype: controller.PendingTasks[index]
                                    ['taskType'] !=
                                null
                            ? controller.PendingTasks[index]['taskType']
                                ['name']
                            : '',
                        projectname: controller.PendingTasks[index]
                                    ['feature'] !=
                                null
                            ? controller.PendingTasks[index]['feature']
                                ['project']['name']
                            : '',
                        feature: controller.PendingTasks[index]
                                    ['feature'] !=
                                null
                            ? controller.PendingTasks[index]['feature']
                                ['name']
                            : '',
                        percent: controller.PendingTasks[index]
                                    ['donePercentage'] !=
                                null
                            ? controller.PendingTasks[index]
                                ['donePercentage']
                            : '',
                        hour:
                            '${controller.PendingTasks[index]['duration']}',
                        date: DateFormat('dd MMM').format(DateTime.parse(
                            '${controller.PendingTasks[index]['createdAt']}')),
                        content: controller.PendingTasks[index]['note'] ==
                                null
                            ? ''
                            : '${controller.PendingTasks[index]['note']}',
                      ),
                    );
                  },
                ),
              )
            : Center(
                child: Text(
                  'no data',
                  style: AppFonts.main_grey_MF,
                ),
              );
  },
);

我尝试用Stack包裹ListView来实现,但这个方案导致ListView无法正常滚动,对应代码如下:

return GetBuilder<HomeController>(
  builder: (controller) {
    return controller.tasksData == null
        ? Center(
            child: SizedBox(
              height: 40,
              width: 40,
              child: CircularProgressIndicator(
                color: AppColor.main_blue,
              ),
            ),
          )
        : controller.PendingTasks.isNotEmpty
            ? Container(
                margin:
                    const EdgeInsets.symmetric(vertical: 20, horizontal: 7),
                child: Stack(
                  children: [
                    ListView.builder(
                      physics: const BouncingScrollPhysics(),
                      itemCount: controller.PendingTasks.length,
                      itemBuilder: (context, index) {
                        return Container(
                          margin: const EdgeInsets.only(bottom: 10),
                          child: TaskCard(
                            tasktype: controller.PendingTasks[index]
                                        ['taskType'] !=
                                    null
                                ? controller.PendingTasks[index]['taskType']
                                    ['name']
                                : '',
                            projectname: controller.PendingTasks[index]
                                        ['feature'] !=
                                    null
                                ? controller.PendingTasks[index]['feature']
                                    ['project']['name']
                                : '',
                            feature: controller.PendingTasks[index]
                                        ['feature'] !=
                                    null
                                ? controller.PendingTasks[index]['feature']
                                    ['name']
                                : '',
                            percent: controller.PendingTasks[index]
                                        ['donePercentage'] !=
                                    null
                                ? controller.PendingTasks[index]
                                    ['donePercentage']
                                : '',
                            hour:
                                '${controller.PendingTasks[index]['duration']}',
                            date: DateFormat('dd MMM').format(DateTime.parse(
                                '${controller.PendingTasks[index]['createdAt']}')),
                            content: controller.PendingTasks[index]['note'] ==
                                    null
                                ? ''
                                : '${controller.PendingTasks[index]['note']}',
                          ),
                        );
                      },
                    ),
                    Container(
                      height: double.infinity,
                      decoration: BoxDecoration(
                        gradient: LinearGradient(
                          begin: Alignment.topCenter,
                          end: Alignment.bottomCenter,
                          colors: [
                            Colors.transparent,
                            Colors.transparent,
                            Colors.black12
                          ]
                        )
                      ),
                    )
                  ],
                ),
              )
            : Center(
                child: Text(
                  'no data',
                  style: AppFonts.main_grey_MF,
                ),
              );
  },
);

我需要实现的效果是阴影容器置于ListView上方,同时保证ListView可正常滚动,参考效果如下:
ListView末尾阴影效果


解决方案

原因分析

Stack中的上层Container默认会拦截所有触摸事件,导致下层的ListView无法接收滚动手势,所以滚动失效。

方法一:让阴影容器穿透触摸事件

给阴影容器添加触摸穿透设置,使其不拦截触摸手势,让事件传递到下层的ListView。注意直接给带渐变的Container设置穿透属性可能会导致渐变不显示,所以需要嵌套一层透明容器:

Stack(
  children: [
    // 原有ListView代码不变
    ListView.builder(...),
    // 修改后的阴影容器
    Container(
      height: double.infinity,
      color: Colors.transparent,
      child: IgnorePointer(
        ignoring: true,
        child: Container(
          decoration: BoxDecoration(
            gradient: LinearGradient(
              begin: Alignment.topCenter,
              end: Alignment.bottomCenter,
              colors: [
                Colors.transparent,
                Colors.transparent,
                Colors.black12
              ]
            )
          ),
        ),
      ),
    )
  ],
)

方法二:将阴影作为ListView的最后一个Item

如果只需要在列表末尾显示阴影(而非覆盖整个列表),可以直接把阴影作为额外的列表项添加,更贴合需求:

ListView.builder(
  physics: const BouncingScrollPhysics(),
  // 列表项数量+1,预留阴影位置
  itemCount: controller.PendingTasks.length + 1,
  itemBuilder: (context, index) {
    // 判断是否为最后一个位置,返回阴影
    if (index == controller.PendingTasks.length) {
      return Container(
        height: 50, // 调整高度适配阴影范围
        margin: const EdgeInsets.only(top: -10), // 和之前的item间距抵消
        decoration: BoxDecoration(
          gradient: LinearGradient(
            begin: Alignment.topCenter,
            end: Alignment.bottomCenter,
            colors: [
              Colors.transparent,
              Colors.black12,
              Colors.black26
            ]
          )
        ),
      );
    }
    // 原有TaskCard代码不变
    return Container(
      margin: const EdgeInsets.only(bottom: 10),
      child: TaskCard(
        tasktype: controller.PendingTasks[index]['taskType'] != null
            ? controller.PendingTasks[index]['taskType']['name']
            : '',
        projectname: controller.PendingTasks[index]['feature'] != null
            ? controller.PendingTasks[index]['feature']['project']['name']
            : '',
        feature: controller.PendingTasks[index]['feature'] != null
            ? controller.PendingTasks[index]['feature']['name']
            : '',
        percent: controller.PendingTasks[index]['donePercentage'] != null
            ? controller.PendingTasks[index]['donePercentage']
            : '',
        hour: '${controller.PendingTasks[index]['duration']}',
        date: DateFormat('dd MMM').format(DateTime.parse('${controller.PendingTasks[index]['createdAt']}')),
        content: controller.PendingTasks[index]['note'] == null
            ? ''
            : '${controller.PendingTasks[index]['note']}',
      ),
    );
  },
)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 09:44:59