Flutter中如何基于ListView索引实现筛选搜索功能?
解决ListView搜索过滤问题:输入“z”时列表无内容
嘿,我来帮你搞定这个搜索功能的问题!目前你的代码里缺少了根据搜索文本过滤列表数据的核心逻辑,所以搜索功能没法正常生效。咱们一步步来修复:
核心思路
- 维护一个
filteredTicketDetails列表,专门存储符合搜索条件的工单数据 - 实现
onSearchTextChanged方法,根据输入文本过滤原列表returnTicketDetails,匹配用户的姓名信息 - 让ListView基于过滤后的列表渲染,而不是直接用原数据
修改后的完整代码
import 'dart:convert'; import 'package:http/http.dart' as http; import 'package:flutter/material.dart'; // 假设你有全局的access_token变量 String access_token = "your_access_token_here"; class TicketScreen extends StatefulWidget { @override _TicketScreenState createState() => _TicketScreenState(); } class _TicketScreenState extends State<TicketScreen> { final TextEditingController controller = TextEditingController(); Map userDetails = {}; List returnTicketDetails = []; // 新增:存储过滤后的工单数据 List filteredTicketDetails = []; @override void initState() { super.initState(); _getTicketDetails(); } void onSearchTextChanged(String text) { setState(() { if (text.isEmpty) { // 搜索框为空时,显示全部数据 filteredTicketDetails = List.from(returnTicketDetails); } else { // 根据用户姓名过滤数据(不区分大小写) filteredTicketDetails = returnTicketDetails.where((ticket) { String firstName = userDetails[ticket["user_id"]]["first_name"].toLowerCase(); String lastName = userDetails[ticket["user_id"]]["last_name"].toLowerCase(); return firstName.contains(text.toLowerCase()) || lastName.contains(text.toLowerCase()); }).toList(); } }); } _getTicketDetails() async { final response = await http.get( Uri.parse("https://your-api-url/tickets"), // 替换成实际API地址 headers: {HttpHeaders.AUTHORIZATION: access_token}, ); returnTicketDetails = json.decode(response.body); // 初始化过滤列表为全部数据 filteredTicketDetails = List.from(returnTicketDetails); for (var i = 0; i < (returnTicketDetails?.length ?? 0); i++) { final ticketresponse = await http.get( Uri.parse("https://your-api-url/users/${returnTicketDetails[i]["user_id"]}"), // 替换成实际用户API地址 headers: {HttpHeaders.AUTHORIZATION: access_token}, ); userDetails[returnTicketDetails[i]["user_id"]] = json.decode(ticketresponse.body); } setState(() {}); } @override Widget build(BuildContext context) { return Scaffold( body: Column( children: <Widget>[ Container( color: Theme.of(context).primaryColor, child: Padding( padding: const EdgeInsets.all(8.0), child: Card( child: ListTile( leading: Icon(Icons.search), title: TextField( controller: controller, decoration: InputDecoration( hintText: 'Search', border: InputBorder.none, ), // 绑定搜索回调 onChanged: onSearchTextChanged, ), trailing: IconButton( icon: Icon(Icons.cancel), onPressed: () { controller.clear(); onSearchTextChanged(''); }, ), ), ), ), ), Expanded( child: filteredTicketDetails.isNotEmpty ? ListView.builder( itemCount: filteredTicketDetails.length, itemBuilder: (context, index) { var ticket = filteredTicketDetails[index]; var user = userDetails[ticket["user_id"]]; return Card( child: Column( mainAxisSize: MainAxisSize.min, children: <Widget>[ Row( children: <Widget>[ Container( width: 80.0, height: 80.0, decoration: BoxDecoration( shape: BoxShape.circle, image: DecorationImage( fit: BoxFit.fill, image: NetworkImage("https://your-image-url.com"), // 替换成实际头像地址 ), ), ), Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(user["first_name"]), Text(user["last_name"]), ], ), ], ), ], ), ); }, ) : Center( // 过滤后无数据时显示提示 child: Text("没有找到匹配的内容"), ), ), ], ), ); } }
关键说明
- 过滤逻辑:在
onSearchTextChanged里,我们把用户名字和输入文本都转成小写再匹配,这样搜索不区分大小写,体验更友好 - ListView渲染:现在完全基于
filteredTicketDetails构建,当输入“z”但没有用户名字包含z时,这个列表会是空的,页面会显示“没有找到匹配的内容”的提示(你也可以自定义空状态UI) - 初始化处理:获取到工单数据后,把
filteredTicketDetails初始化为全部数据,保证页面加载时显示完整列表
这样修改后,你的搜索功能就能正常工作啦!
内容的提问来源于stack exchange,提问作者heyr
相关产品推荐
相关产品推荐

