Flutter中ListView搜索过滤功能失效问题求助
Flutter ListView 搜索过滤功能修复
问题根源分析
原searchHisse()方法存在三个核心错误:
- 类型匹配错误:将过滤后的
List<Result>直接强转为Hisselist类型,导致类型不兼容 - 过滤逻辑错误:试图用字符串去匹配
Result对象列表,永远无法命中结果 - 无原始数据备份:搜索后无法恢复初始的完整数据列表
修复方案
- 添加原始数据备份变量,保存API返回的完整数据
- 修正过滤逻辑,针对
Result对象的text或code字段进行关键词匹配 - 正确构建
Hisselist对象更新状态,同时维护列表长度计数器
修复后的完整代码
class Hisseler extends StatefulWidget { const Hisseler({Key? key}) : super(key: key); @override State<Hisseler> createState() => _HisselerState(); } class _HisselerState extends State<Hisseler> { final controller = TextEditingController(); final scaffoldKey = GlobalKey<ScaffoldState>(); final url = Uri.parse('https://api.collectapi.com/economy/hisseSenedi'); var counter; Hisselist? hisseResult; // 新增:保存原始数据,用于搜索恢复 Hisselist? originalHisseResult; Future callHisse() async { try{ Map<String, String> requestHeaders = { 'Content-Type': 'application/json', 'Authorization': 'apikey xxx:xxx' }; final response = await http.get(url,headers:requestHeaders); if(response.statusCode == 200){ var result = hisselistFromJson(response.body); result.result.sort((a, b) => (a.text ?? "").compareTo(b.text ?? "")); if(mounted){ setState(() { counter = result.result.length; hisseResult = result; // 初始化原始数据备份 originalHisseResult = result; }); } return result; } else { print(response.statusCode); } } catch(e) { print(e.toString()); } } @override void initState() { super.initState(); callHisse(); } @override Widget build(BuildContext context) { final style = controller.text.isEmpty ? const TextStyle(color: Colors.black54) : const TextStyle(color: Colors.black); return Scaffold( appBar: AppBar( centerTitle: false, automaticallyImplyLeading: false, title: const Text('Hisseler'), ), body: Column( children: [ Container( margin: const EdgeInsets.fromLTRB(16, 16, 16, 16), child: TextField( controller: controller, decoration: InputDecoration( prefixIcon: const Icon(Icons.search), suffixIcon: controller.text.isNotEmpty ? GestureDetector( child: Icon(Icons.close, color: style.color), onTap: () { controller.clear(); FocusScope.of(context).requestFocus(FocusNode()); searchHisse(''); }, ) : null, hintText: 'Hisse Ara', border: OutlineInputBorder( borderRadius: BorderRadius.circular(20), borderSide: const BorderSide(color: Colors.black26), ), ), onChanged: searchHisse, ), ), Expanded( child: Center( child: Padding( padding: const EdgeInsets.all(8.0), child: counter != null ? ReorderableListView.builder( itemCount: counter, itemBuilder: (context, index){ final item = hisseResult?.result[index]; return Card( key: ValueKey(item), child: ListTile( contentPadding: const EdgeInsets.all(10), title: Column( crossAxisAlignment: CrossAxisAlignment.start, children: <Widget>[ Text((item?.code ?? "").replaceAll("https:", ""), style: const TextStyle( color: Colors.black, fontSize: 16, fontWeight: FontWeight.w500)), Text(item?.text ?? "",style: TextStyle(color: Colors.grey[500], fontSize: 14)) ], ), trailing: Column( children: <Widget>[ Text(item?.lastpricestr ?? "", style: const TextStyle(color: Colors.black, fontSize: 16, fontWeight: FontWeight.w500)), Container( alignment: Alignment.center, decoration: BoxDecoration( borderRadius: BorderRadius.circular(5), color: (item?.rate ?? 0) > 0 ? Colors.green : Colors.red), width: 75, height: 25, child: Text(item?.rate.toString() ?? "", style: const TextStyle(color: Colors.white))) ], ), onTap: () => Navigator.push( context, MaterialPageRoute(builder: (context) => StocksDetailScreen( degisimoran: item?.rate?.toDouble(), sondeger: item?.lastpricestr ?? "", hacim: item?.hacimstr ?? "", mindeger : item?.minstr ?? "", maxdeger : item?.maxstr ?? "", hisseismi : item?.text ?? "", hissekodu : item?.code ?? "", min : item?.min?.toDouble(), max : item?.max?.toDouble(), son : item?.lastprice?.toDouble(), )), ), ), ); }, onReorder: (oldIndex, newIndex) { setState(() { if (newIndex > oldIndex) { newIndex = newIndex - 1; } final element = hisseResult?.result.removeAt(oldIndex); if(element != null){ hisseResult?.result.insert(newIndex, element); } }); }, ) : const Center(child: CircularProgressIndicator()), ), ), ), ], ), ); } void searchHisse(String query) { if(originalHisseResult == null) return; final input = query.toLowerCase().trim(); List<Result> filteredResults; if(input.isEmpty){ // 空输入时恢复原始数据 filteredResults = originalHisseResult!.result; } else { // 过滤逻辑:匹配股票名称或代码 filteredResults = originalHisseResult!.result.where((result) { final text = result.text?.toLowerCase() ?? ""; final code = result.code?.toLowerCase() ?? ""; return text.contains(input) || code.contains(input); }).toList(); } setState(() { // 构建新的Hisselist对象更新状态 hisseResult = Hisselist( success: originalHisseResult!.success, result: filteredResults, ); counter = filteredResults.length; }); } }
关键修复点说明
- 添加
originalHisseResult变量存储原始API响应数据,确保搜索清空后能恢复完整列表 - 修改
searchHisse方法,针对Result对象的text和code字段做小写转换后匹配关键词,避免大小写敏感问题 - 空输入时直接恢复原始数据,非空输入时过滤后生成新的
Hisselist对象,保证类型匹配 - 优化了
onReorder中的空值判断,避免潜在的空指针异常
内容的提问来源于stack exchange,提问作者Mıktad Tahir Durak
相关产品推荐
相关产品推荐

