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可正常滚动,参考效果如下:
解决方案
原因分析
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
相关产品推荐
相关产品推荐

