How to use SearchDelegate to show recent search history in flutter?

后端 未结 1 1951
予麋鹿
予麋鹿 2021-01-14 12:59

I want to use showSearch to get the search text( or query) from user. I also want to show the recent searches as suggestion and filter search history based on t

相关标签:
1条回答
  • 2021-01-14 13:27

    custom_search_delgates.dart

    import 'package:flutter/material.dart';
    
    typedef OnSearchChanged = Future<List<String>> Function(String);
    
    class SearchWithSuggestionDelegate extends SearchDelegate<String> {
      ///[onSearchChanged] gets the [query] as an argument. Then this callback
      ///should process [query] then return an [List<String>] as suggestions.
      ///Since its returns a [Future] you get suggestions from server too.
      final OnSearchChanged onSearchChanged;
    
      ///This [_oldFilters] used to store the previous suggestions. While waiting
      ///for [onSearchChanged] to completed, [_oldFilters] are displayed.
      List<String> _oldFilters = const [];
    
      SearchWithSuggestionDelegate({String searchFieldLabel, this.onSearchChanged})
          : super(searchFieldLabel: searchFieldLabel);
    
      ///
      @override
      Widget buildLeading(BuildContext context) {
        return IconButton(
          icon: const Icon(Icons.arrow_back),
          onPressed: () => Navigator.pop(context),
        );
      }
    
      @override
      List<Widget> buildActions(BuildContext context) {
        return [
          IconButton(
            icon: Icon(Icons.clear),
            onPressed: () => query = "",
          ),
        ];
      }
    
      ///OnSubmit in the keyboard, returns the [query]
      @override
      void showResults(BuildContext context) {
        close(context, query);
      }
    
      ///Since [showResults] is overridden we can don't have to build the results.
      @override
      Widget buildResults(BuildContext context) => null;
    
      @override
      Widget buildSuggestions(BuildContext context) {
        return FutureBuilder<List<String>>(
          future: onSearchChanged != null ? onSearchChanged(query) : null,
          builder: (context, snapshot) {
            if (snapshot.hasData) _oldFilters = snapshot.data;
            return ListView.builder(
              itemCount: _oldFilters.length,
              itemBuilder: (context, index) {
                return ListTile(
                  leading: Icon(Icons.restore),
                  title: Text("${_oldFilters[index]}"),
                  onTap: () => close(context, _oldFilters[index]),
                );
              },
            );
          },
        );
      }
    }
    

    Usage:

    import 'package:flutter/material.dart';
    import 'package:flutter_app/custom_search_delgates.dart';
    import 'package:shared_preferences/shared_preferences.dart';
    
    void main() {
      runApp(MaterialApp(home: Home()));
    }
    
    class Home extends StatefulWidget {
      @override
      _HomeState createState() => _HomeState();
    }
    
    class _HomeState extends State<Home> {
      Future<void> _showSearch() async {
        final searchText = await showSearch<String>(
          context: context,
          delegate: SearchWithSuggestionDelegate(
            onSearchChanged: _getRecentSearchesLike,
          ),
        );
    
        //Save the searchText to SharedPref so that next time you can use them as recent searches.
        await _saveToRecentSearches(searchText);
    
        //Do something with searchText. Note: This is not a result.
      }
    
      Future<List<String>> _getRecentSearchesLike(String query) async {
        final pref = await SharedPreferences.getInstance();
        final allSearches = pref.getStringList("recentSearches");
        return allSearches.where((search) => search.startsWith(query)).toList();
      }
    
      Future<void> _saveToRecentSearches(String searchText) async {
        if (searchText == null) return; //Should not be null
        final pref = await SharedPreferences.getInstance();
    
        //Use `Set` to avoid duplication of recentSearches
        Set<String> allSearches =
            pref.getStringList("recentSearches")?.toSet() ?? {};
    
        //Place it at first in the set
        allSearches = {searchText, ...allSearches};
        pref.setStringList("recentSearches", allSearches.toList());
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text("Search Demo"),
            actions: <Widget>[
              IconButton(
                icon: Icon(Icons.search),
                onPressed: _showSearch,
              ),
            ],
          ),
        );
      }
    }
    
    0 讨论(0)
提交回复
热议问题