You can see that when the search bar is engaged we can show historical search and search suggestions as we type the query.

Here first we create simple ListView which is display city list.After that implement SearchDelegate for define the content of the search page.Then the results can be brought on screen by calling SearchDelegate.showResults and you can go back to showing the suggestions by calling SearchDelegate.showSuggestions.Let’s take a look at how we do all this in code.
Create Search Delegate
The appearance of the search page is determined by the Search delegate class. First, create a class that extends the abstract class SearchDelegate
.
class _MySearchDelegate extends SearchDelegate<String> {
final List<String> city_names;
final List<String> _history = ["Aurora","Austin",
"Bakersfield","Baltimore","Barnstable","Baton Rouge"];
List<String> filterName = new List();
_MySearchDelegate(this.city_names);
@override
List<Widget> buildActions(BuildContext context) {
return <Widget>[
IconButton(
tooltip: 'Clear',
icon: const Icon((Icons.clear)),
onPressed: () {
query = '';
showSuggestions(context);
},
)
];
}
@override
Widget buildLeading(BuildContext context) {
return IconButton(
icon: AnimatedIcon(
icon: AnimatedIcons.menu_arrow, progress: transitionAnimation),
onPressed: () {
close(context, null);
},
);
}
@override
Widget buildResults(BuildContext context) {
return Text(query);
}
@override
Widget buildSuggestions(BuildContext context) {
final suggestions = query.isEmpty
? _history
: city_names.where((c) => c.toLowerCase().contains(query)).toList();
return ListView.builder(
itemCount: suggestions.length,
itemBuilder: (BuildContext context, int index) {
return new ListTile(
title: Text(suggestions[index]),
onTap: () {
// showResults(context);
close(context, suggestions[index]);
},
);
});
}
}
buildActions
display ActionButtons after the search query in the AppBar.This should typically contain a button to clear the query.buildLeading
Typically an IconButton configured with a BackButtonIcon that exits the search with close.
Override the buildSuggestions
and buildResults
functions and return what you want to be shown. In our example, it’s a list view of text when the user is typing. Once the user has selected a search result, SearchDelegate.close should be called to remove the search page from the top of the navigation stack
Every search delegate has a query stream. When it’s empty, we return a list view populated with historical search queries and when they’ve entered at least one character, It returns the string that contains that query in a list view.
showSearch
Calling the showSearch function will open a search text field and underneath it, the list view will return the build suggestions.
actions: <Widget>[
IconButton(
icon: const Icon(Icons.search),
onPressed: () async {
final String selected = await showSearch(
context: context, delegate: _MySearchDelegate(city_names));
if (selected != null && selected != query) {
setState(() {
query = selected;
});
}
},
)
],
This method returns the selected search result, which can be set in the SearchDelegate.close call. If the search page is closed with the system back button, it returns null.
Complete example
import 'package:flutter/material.dart';
import 'package:dio/dio.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Expandable Search',
theme: ThemeData(
primarySwatch: Colors.pink,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
final List<String> city_names = [
"Aberdeen",classAurora","Austin","Bakersfield","York",
"Youngstown"....];
final dio = new Dio();
String query = '';
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Search"),
actions: <Widget>[
IconButton(
icon: const Icon(Icons.search),
onPressed: () async {
final String selected = await showSearch(
context: context, delegate: _MySearchDelegate(city_names));
if (selected != null && selected != query) {
setState(() {
query = selected;
});
}
},
)
],
),
body: Container(
child: _buildList(''),
),
resizeToAvoidBottomPadding: false,
);
}
Widget _buildList(_searchText) {
final searchItems = query.isEmpty
? city_names
: city_names
.where((c) => c.toLowerCase().contains(query.toLowerCase()))
.toList();
return ListView.builder(
itemCount: searchItems.length,
itemBuilder: (BuildContext context, int index) {
return new ListTile(
title: Text((searchItems[index])),
leading: Icon(Icons.location_city),
subtitle: Text('Search'),
);
},
);
}
}
class _MySearchDelegate extends SearchDelegate<String> {
final List<String> city_names;
final List<String> _history = [
"Aurora",
"Austin",
"Bakersfield",
"Baltimore",
"Barnstable",
"Baton Rouge",
"Beaumont",
"Bel Air",
"Bellevue",
"Berkeley",
"Bethlehem"
];
List<String> filterName = new List();
_MySearchDelegate(this.city_names);
@override
List<Widget> buildActions(BuildContext context) {
return <Widget>[
IconButton(
tooltip: 'Clear',
icon: const Icon((Icons.clear)),
onPressed: () {
query = '';
showSuggestions(context);
},
)
];
}
@override
Widget buildLeading(BuildContext context) {
return IconButton(
icon: AnimatedIcon(
icon: AnimatedIcons.menu_arrow, progress: transitionAnimation),
onPressed: () {
close(context, null);
},
);
}
@override
Widget buildResults(BuildContext context) {
return Text(query);
}
@override
Widget buildSuggestions(BuildContext context) {
final suggestions = query.isEmpty
? _history
: city_names.where((c) => c.toLowerCase().contains(query)).toList();
return ListView.builder(
itemCount: suggestions.length,
itemBuilder: (BuildContext context, int index) {
return new ListTile(
title: Text(suggestions[index]),
onTap: () {
// showResults(context);
close(context, suggestions[index]);
},
);
});
}
}