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

如何在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 15:15:30