如何在Flutter中使用Provider结合Post API实现搜索筛选功能?
Flutter中结合Provider与Post API实现搜索筛选功能
一、更新LibraryProvider逻辑
在你的LibraryProvider中添加搜索相关的状态管理和API调用方法,区分原始库数据与搜索结果:
import 'package:flutter/foundation.dart'; import '../models/Searchmodel.dart'; import '../services/Services.dart'; class LibraryProvider extends ChangeNotifier { List<dynamic> library = []; // 原始库数据 List<Searchmodel> searchResults = []; // 搜索结果 bool isLoading = false; bool isSearching = false; // 标记是否处于搜索状态 // 加载原始库数据(保留你原有逻辑) Future<void> fetchLibrary() async { isLoading = true; notifyListeners(); // --- 这里放入你原本的fetchLibrary实现代码 --- isLoading = false; notifyListeners(); } // 执行搜索请求 Future<void> performSearch(String keyword) async { if (keyword.isEmpty) { isSearching = false; notifyListeners(); return; } isLoading = true; isSearching = true; notifyListeners(); try { searchResults = await Services().Search(keyword); // 调用你提供的Post API } catch (e) { if (kDebugMode) print('搜索错误: $e'); searchResults = []; } finally { isLoading = false; notifyListeners(); } } // 清空搜索,回到原始数据展示 void clearSearch() { isSearching = false; searchResults = []; notifyListeners(); } }
二、修改Homepage实现搜索交互
添加搜索输入控制器,处理输入事件和搜索触发,并根据Provider状态切换展示数据:
import 'package:flutter/material.dart'; import 'package:livinghopegeetzaboor/Statemanagment/Library/LibraryProvider.dart'; import 'package:livinghopegeetzaboor/constant/AppColor.dart'; import 'package:livinghopegeetzaboor/sacreen/Geet/Geetsubcategory.dart'; import 'package:livinghopegeetzaboor/services/Services.dart'; import 'package:provider/provider.dart'; class Homepage extends StatefulWidget { @override State<Homepage> createState() => _HomepageState(); } class _HomepageState extends State<Homepage> { final TextEditingController _searchController = TextEditingController(); @override void dispose() { _searchController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return SingleChildScrollView( child: Center( child: Padding( padding: const EdgeInsets.fromLTRB(0, 0, 0, 0), child: Container( child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ Container( height: 100, width: 100, child: Image.asset('images/logo.png'), ), Padding( padding: const EdgeInsets.all(40), child: Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(20.0), color: AppColor.color, ), height: 80, child: Padding( padding: const EdgeInsets.all(8.0), child: Row( children: [ Expanded( child: TextField( controller: _searchController, decoration: InputDecoration( suffixIcon: IconButton( icon: const Icon(Icons.search, size: 40), onPressed: () { // 点击搜索图标触发搜索 Provider.of<LibraryProvider>(context, listen: false) .performSearch(_searchController.text.trim()); }, ), enabledBorder: const OutlineInputBorder( borderSide: BorderSide(color: Colors.white, width: 2), ), filled: true, fillColor: Colors.white, border: OutlineInputBorder( borderRadius: BorderRadius.circular(20), ), hintText: 'Search for any songs', ), onChanged: (value) { // 实时输入触发搜索(可根据需求改为点击按钮触发) Provider.of<LibraryProvider>(context, listen: false) .performSearch(value.trim()); }, ), ), const SizedBox(width: 3), // 清空搜索按钮(仅在有输入时显示) if (_searchController.text.isNotEmpty) IconButton( icon: const Icon(Icons.clear, color: Colors.white, size: 30), onPressed: () { _searchController.clear(); Provider.of<LibraryProvider>(context, listen: false).clearSearch(); }, ), ], ), ), ), ), Consumer<LibraryProvider>( builder: (BuildContext context, provider, Widget? child) { if (provider.isLoading) { return const CircularProgressIndicator(color: AppColor.color); } else { // 根据搜索状态选择展示数据 final displayList = provider.isSearching ? provider.searchResults : provider.library; return GridView.builder( itemCount: displayList.length, scrollDirection: Axis.vertical, shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), // 解决嵌套滚动冲突 gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 3, crossAxisSpacing: 4.0, mainAxisSpacing: 4.0, ), itemBuilder: (BuildContext context, int index) { final item = displayList[index]; // 处理不同数据类型的字段映射 String name = item is Searchmodel ? (item.name ?? '') : (item.name ?? ''); String? name2 = item is Searchmodel ? null : item.name2; int? id = item is Searchmodel ? item.id : item.id; return Padding( padding: const EdgeInsets.all(10), child: Material( color: Colors.white.withOpacity(0.0), child: InkWell( splashColor: Colors.orange, child: Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(10.0), color: Colors.black, ), height: 200, width: 200, child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ Padding( padding: const EdgeInsets.all(5), child: Center( child: Text( name, style: const TextStyle( color: Colors.white, fontWeight: FontWeight.bold, fontSize: 18, ), ), ), ), const SizedBox(height: 4), if (name2 != null) Padding( padding: const EdgeInsets.fromLTRB(10, 0, 0, 0), child: Center( child: Text( name2, style: const TextStyle( color: Colors.white, fontSize: 12, ), ), ), ), ], ), ), onTap: () { Navigator.push( context, MaterialPageRoute( builder: (context) => Geetsubcategory(id: id), ), ); }, ), ), ); }, ); } }, ), ], ), ), ), ), ); } @override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) { Provider.of<LibraryProvider>(context, listen: false).fetchLibrary(); }); } }
三、关键注意点
- 确保
Services类正确导出Search方法,让Provider可以调用 - 若原始
library数据与Searchmodel结构差异大,需在UI中做好类型判断和字段适配 - 搜索触发时机可自由选择:实时输入触发或点击搜索按钮触发
- 处理空关键词场景,自动回到原始数据展示
内容的提问来源于stack exchange,提问作者mark anthony
相关产品推荐
相关产品推荐

