Flutter Web中FutureBuilder嵌套GridView的Ink.image不显示问题
问题原因
- Future重复触发导致组件反复重建:代码中FutureBuilder的
future参数直接调用productsPageController.getProducts()方法,外层包裹的Obx响应式组件触发重绘时,会反复生成新的Future实例,导致GridView不断销毁重建,Ink.image的图片加载流程被反复中断,无法完成渲染上屏。 - Flutter 2.5.x Web端已知渲染Bug:该版本Web端(尤其是使用CanvasKit渲染模式时)存在异步构建列表中
Ink.image渲染丢失的问题,异步返回后首次构建的Ink组件无法正确关联父级Material上下文的着色器,导致图片加载完成后不会触发绘制操作。 - ImageProvider类型推断异常:代码中
image变量声明为无类型的late final,默认推断为dynamic类型,部分场景下Ink.image无法正确识别ImageProvider类型,加载完成后不会触发UI更新。
解决方法
1. 缓存Future避免重复执行
不要在FutureBuilder的future参数中直接调用异步方法,提前在控制器中缓存Future实例,避免重绘时反复触发异步请求和组件重建:
首先在ProductsPageController中添加缓存变量:
// 在ProductsPageController类中新增 Future<List<ProductModel>>? productsFuture;
在下拉选项切换时重新赋值Future:
onChanged: (SupplierModel? newValue) { productsPageController.dropdownValue.value = newValue; // 切换供应商时仅重新加载一次产品,缓存future实例 productsPageController.productsFuture = productsPageController.getProducts(); }
修改FutureBuilder的future参数为缓存的实例:
FutureBuilder( future: productsPageController.productsFuture, builder: (context, snapshot) { // 原有构建逻辑保持不变 } )
2. 修复Ink.image上下文兼容问题
如果需要保留Ink的水波纹效果,可在Ink.image外层包裹Material组件,手动提供Material上下文:
Container( child: Material( child: Ink.image( // 原有参数保持不变 ), ), )
如果不需要水波纹附着在图片上,可直接替换为Image组件嵌套InkWell的写法,彻底规避Ink组件的兼容问题:
Container( width: 120, height: 120, child: InkWell( onTap: () {/* 原有点击逻辑 */}, child: Image( image: image, fit: BoxFit.fill, errorBuilder: (context, error, stackTrace) { print("Image Error: $error"); return const SizedBox(); }, ), ), )
3. 明确ImageProvider类型
修改image变量的声明,明确指定类型为ImageProvider,避免类型推断异常:
// 替换原有无类型声明 late final ImageProvider image;
4. (可选)升级Flutter版本
该渲染Bug在Flutter 2.10及以上稳定版本已经修复,若业务允许升级Flutter版本,升级到最新稳定版可直接解决该问题。
内容的提问来源于stack exchange,提问作者Kin Pu
相关产品推荐
相关产品推荐

