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

Flutter中ListView搜索过滤功能失效问题求助

Flutter ListView 搜索过滤功能修复

问题根源分析

原searchHisse()方法存在三个核心错误:

  • 类型匹配错误:将过滤后的List<Result>直接强转为Hisselist类型,导致类型不兼容
  • 过滤逻辑错误:试图用字符串去匹配Result对象列表,永远无法命中结果
  • 无原始数据备份:搜索后无法恢复初始的完整数据列表

修复方案

  1. 添加原始数据备份变量,保存API返回的完整数据
  2. 修正过滤逻辑,针对Result对象的text或code字段进行关键词匹配
  3. 正确构建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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 14:14:39