Flutter中解决FutureBuilder+ListView搜索输入异常的方法
问题修复方案
核心问题分析
你的问题源于两个关键错误:
- 第一页
FutureBuilder每次重建都会重新发起异步请求,导致第二页被反复实例化,输入状态丢失; - 第二页动态替换
appBarTitle为TextField,每次setState都会重建输入框,无法维持输入焦点与内容。
以下是针对性修复代码及说明:
第一页(数据获取页)修复
class firstPage extends StatefulWidget { @override _HomePageState createState() => _HomePageState(); } class _HomePageState extends State<firstPage> { late Future<List<AllProductModel>> _productsFuture; @override void initState() { super.initState(); // 仅在初始化时发起一次异步请求,避免重复加载 _productsFuture = fetchYourProduct(Uids, NameUserContry); } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: kBackground, body: Center( child: Column( children: [ Expanded( child: FutureBuilder<List<AllProductModel>>( future: _productsFuture, // 使用预初始化的Future变量 builder: (context, snapshot) { final ListDataDisplay = snapshot.data; switch (snapshot.connectionState) { case ConnectionState.waiting: return const Center(child: CircularProgressIndicator()); default: if (snapshot.hasError) { return const Center(child: Text('Some error occurred!')); } else if (ListDataDisplay == null) { return const Center(child: Text('No data available')); } else { return UserPage(ListDataDisplay: ListDataDisplay); } } }, ), ) ], ), ), ); } }
修复说明
- 将异步请求移至
initState中执行,保存为成员变量_productsFuture,确保仅发起一次请求,避免组件重建时重复加载数据。
第二页(搜索列表页)修复
class UserPage extends StatefulWidget { final List<AllProductModel> ListDataDisplay; UserPage({Key? key, required this.ListDataDisplay}) : super(key: key); @override State<UserPage> createState() => _UserPageState(); } class _UserPageState extends State<UserPage> { final TextEditingController searchController = TextEditingController(); late List<AllProductModel> _filteredList; bool _isSearching = false; @override void initState() { super.initState(); _filteredList = widget.ListDataDisplay; // 监听搜索框输入,实时过滤数据 searchController.addListener(() { setState(() { final searchText = searchController.text.toLowerCase(); _filteredList = widget.ListDataDisplay.where((product) { return product.name.toLowerCase().contains(searchText) || product.coponId.toLowerCase().contains(searchText); }).toList(); }); }); } @override void dispose() { searchController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( centerTitle: true, title: _isSearching ? TextField( controller: searchController, style: const TextStyle(color: Colors.black), decoration: const InputDecoration( labelText: 'Name', enabledBorder: UnderlineInputBorder( borderSide: BorderSide(color: Colors.black), ), ), autofocus: true, ) : const Text("List"), backgroundColor: CustomColors.firebaseGrey, elevation: 1.5, actions: [ IconButton( onPressed: () { setState(() { _isSearching = !_isSearching; if (!_isSearching) { searchController.clear(); _filteredList = widget.ListDataDisplay; } }); }, icon: Icon( _isSearching ? Icons.close : Icons.search, color: CustomColors.firebaseNavy, ), ), ], ), body: ListView.builder( physics: const ScrollPhysics(), scrollDirection: Axis.vertical, shrinkWrap: true, itemCount: _filteredList.length, itemBuilder: (context, index) { final product = _filteredList[index]; return Card( elevation: 1.5, child: Container( padding: const EdgeInsets.all(6), child: Row( children: [ Text(product.name), ], ), ), ); }, ), ); } }
修复说明
- 避免输入框重建:使用
_isSearching状态变量控制标题栏显示内容,TextField始终为同一个实例,不会因setState丢失输入状态; - 优化搜索逻辑:维护
_filteredList变量,提前过滤数据,避免在itemBuilder中生成大量空容器,提升性能; - 修正搜索判断:改为分别判断名称和
coponId是否包含搜索内容,同时忽略大小写,提升搜索体验。
内容的提问来源于stack exchange,提问作者M Al
相关产品推荐
相关产品推荐

