Flutter移除列表项后ExpansionTile触发类型转换错误
问题:移除ListView列表项后出现类型转换错误
移除列表项后抛出以下错误:
The following _CastError was thrown building SingleChildScrollView(dependencies: [PrimaryScrollController]): type 'bool' is not a subtype of type 'double?' in type cast The relevant error-causing widget was: When the exception was thrown, this was the stack: #0 ScrollPosition.restoreScrollOffset (package:flutter/src/widgets/scroll_position.dart:420:103) #1 new ScrollPosition (package:flutter/src/widgets/scroll_position.dart:105:7) #2 new ScrollPositionWithSingleContext (package:flutter/src/widgets/scroll_position_with_single_context.dart:56:8) #3 ScrollableState._updatePosition (package:flutter/src/widgets/scrollable.dart:406:10) #4 ScrollableState.didChangeDependencies (package:flutter/src/widgets/scrollable.dart:431:5)
相关代码
列表定义:
List<dynamic> RefrigCarNo = [];
ListView构建代码:
ListView.builder( shrinkWrap: true, itemCount: RefrigCarNo.length, itemBuilder: (BuildContext context, int index) { return Card( color: getColor(context, index), key: new PageStorageKey(RefrigCarNo[0].elementAt(index)), // 此处key设置存在问题 child: ExpansionTile( maintainState: CollapseState, title: RichText( textDirection: TextDirection.rtl, text: TextSpan( style: label_A, children: [ TextSpan(text: 'refrigCar'), TextSpan(text: ' ${RefrigCarNo[index][1].toString()} ') ] ) ), children: [ Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Container( margin: EdgeInsets.fromLTRB(0, 10, 0, 3), width: PageWidth * 0.4, color: Colors.white, child: Column( children: [ Text('Kg Of Material', style: label_A,), AppTextField1( MyController: Weight, MyValidation: false, typeOfInput: TextInputType.number, myReadOnly: readOnlyChange, ), ], ), ), Container( margin: EdgeInsets.fromLTRB(0, 10, 0, 3), width: PageWidth * 0.3, color: Colors.white, child: Column( children: [ Text('Total Net', style: label_A,), AppTextField1( MyController: NetCalcWeight, MyValidation: false, typeOfInput: TextInputType.number, myReadOnly: readOnlyChange, ), ], ), ), ], ), ], ), ); }),
删除列表项函数:
void onDeleteVar(int _index) async{ setState(() { RefrigCarNo.removeAt(_index); }); }
解决方案
错误根源是PageStorageKey重复/冲突,导致滚动偏移量的存储被ExpansionTile的bool类型展开状态覆盖,进而触发类型转换错误。按以下步骤修复:
保证PageStorageKey的唯一性
给Card和ExpansionTile分别设置独立的唯一key,避免键冲突:return Card( color: getColor(context, index), key: PageStorageKey('card_refrig_car_${RefrigCarNo[index][1]}'), child: ExpansionTile( key: PageStorageKey('expansion_refrig_car_${RefrigCarNo[index][1]}'), maintainState: CollapseState, // ...其他原有代码 ), );为每个列表项单独维护TextField控制器
当前所有项复用同一个Weight和NetCalcWeight控制器,会导致状态混乱。修改列表结构,让每个元素自带专属控制器:// 添加新项的示例代码 void addNewRefrigCar() { setState(() { RefrigCarNo.add({ 'carNo': '新车辆编号', // 替换为实际车辆标识 'weightController': TextEditingController(), 'netController': TextEditingController(), }); }); }然后在ListView中调用对应项的控制器:
AppTextField1( MyController: RefrigCarNo[index]['weightController'], MyValidation: false, typeOfInput: TextInputType.number, myReadOnly: readOnlyChange, ), // ... AppTextField1( MyController: RefrigCarNo[index]['netController'], MyValidation: false, typeOfInput: TextInputType.number, myReadOnly: readOnlyChange, ),删除项时清理对应PageStorage数据
删除列表项后,手动清理该项对应的PageStorage存储,并销毁控制器避免内存泄漏:void onDeleteVar(int _index) { final carId = RefrigCarNo[_index][1]; // 清理Card和ExpansionTile的PageStorage数据 PageStorage.of(context)?.writeState(context, null, identifier: PageStorageKey('card_refrig_car_$carId')); PageStorage.of(context)?.writeState(context, null, identifier: PageStorageKey('expansion_refrig_car_$carId')); // 销毁控制器 RefrigCarNo[_index]['weightController'].dispose(); RefrigCarNo[_index]['netController'].dispose(); setState(() { RefrigCarNo.removeAt(_index); }); }
内容的提问来源于stack exchange,提问作者Hamed Zahiri
相关产品推荐
相关产品推荐

