Flutter 从API拉取名言列表时SearchDelegate无搜索结果如何解决?
问题根因
- Search类中定义的接口请求方法
getPost从未触发调用,存储名言的quotes数组始终为空,无数据可筛选 - 筛选逻辑存在类型错误:
quotes中存储的是包含text、author字段的Map对象,直接对Map对象调用toLowerCase()无法匹配到搜索词 - 接口请求冗余:ListPage页面已经完成全量名言数据拉取,Search中重复请求属于不必要的资源浪费
- 列表渲染逻辑错误:直接将Map对象作为Text组件的内容,会导致渲染异常
修复方案
1. 重构Search类,支持接收外部传入数据、修正筛选与渲染逻辑
import 'package:flutter/material.dart'; class Search extends SearchDelegate<String> { final List quotes; // 接收外部传入的已拉取名言数据 String result = ""; Search({ required this.quotes, }); @override List<Widget> buildActions(BuildContext context) { return [ IconButton( icon: const Icon(Icons.clear), onPressed: () { query = ''; }, ) ]; } @override Widget buildLeading(BuildContext context) { return IconButton( icon: const Icon(Icons.arrow_back), onPressed: () { close(context, result); }, ); } @override Widget buildResults(BuildContext context) { final suggestions = quotes.where((quoteItem) { final quoteText = quoteItem["text"]?.toString().toLowerCase() ?? ""; final quoteAuthor = quoteItem["author"]?.toString().toLowerCase() ?? ""; final queryLower = query.toLowerCase(); // 同时匹配名言内容和作者 return quoteText.contains(queryLower) || quoteAuthor.contains(queryLower); }).toList(); return ListView.builder( itemCount: suggestions.length, itemBuilder: (BuildContext context, int index) { final item = suggestions[index]; return ListTile( title: Text(item["text"] ?? ""), subtitle: Text(item["author"] ?? "未知作者", style: const TextStyle(color: Colors.redAccent),), onTap: () { result = item["text"] ?? ""; close(context, result); }, ); }, ); } @override Widget buildSuggestions(BuildContext context) { // 建议列表和结果列表共用同一筛选逻辑 return buildResults(context); } }
2. 修改ListPage代码,缓存已拉取数据并传入Search实例
import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; // 导入你修改后的Search类 import 'package:flutterquote/model/search.dart'; class ListPage extends StatefulWidget { @override _ListPageState createState() => _ListPageState(); } class _ListPageState extends State<ListPage> { List _allQuotes = []; // 缓存全量名言数据 Future<List<dynamic>> getPost() async { final response = await http.get(Uri.https('type.fit', 'api/quotes')); return postFromJson(response.body); } List<dynamic> postFromJson(String str) { List<dynamic> jsonData = json.decode(str); _allQuotes = jsonData.toList(); // 拉取成功后缓存全量数据 return jsonData; } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: const Color(0xff171717), appBar: AppBar( toolbarHeight: 80, title: const Text(''), backgroundColor: Colors.transparent, elevation: 0, actions: <Widget>[ IconButton( icon: const Icon(Icons.search, color: Colors.white,), onPressed: () async { final result = await showSearch<String>( context: context, // 将缓存的全量数据传入Search实例 delegate: Search(quotes: _allQuotes), ); print(result); }, ) ], ), body: Container( color: const Color(0xff171717), child: FutureBuilder( future: getPost(), builder: (BuildContext context, AsyncSnapshot snapshot) { if (snapshot.connectionState == ConnectionState.done) { if (snapshot.hasError) { print(snapshot); return ErrorWidget(snapshot); } return ListView.separated( itemCount: snapshot.data.length, itemBuilder: (BuildContext context, int index) { var model = snapshot.data![index]; return ListTile( leading: const Icon(Icons.format_quote, color: Colors.white,), title: Text( model["text"].toString(), style: const TextStyle(color: Colors.white), ), subtitle: Text( model["author"].toString(), style: const TextStyle(color: Colors.redAccent), ), ); }, separatorBuilder: (BuildContext context, int index) { return const SizedBox( height: 20, ); }, ); } else return const Center(child: CircularProgressIndicator(color: Colors.white,)); }, ), )); } }
可选优化
你已经定义了QuoteModel类,可以将接口返回的Map数据统一转换为QuoteModel实例操作,避免直接操作Map出现字段名拼写错误等问题。
内容的提问来源于stack exchange,提问作者Robin Rivera
相关产品推荐
相关产品推荐

