I'm looking for a search bar in flutter docs but can't find it, is there a widget for the search bar with autocomplete in appbar. For example, I have a search icon on my appbar. When one press it show's the search box, when you type it should show autocomplete from the dropdown with listtile. I managed to implement this but it's not easy to use because I need a dropdown to show suggestion autocomplete, then use the suggestion for a new route if selected.
Here the search action
You can use Stack to achieve the autocomplete dropdown box effect. Example below has 2 Containers - both hold ListView
as child objects. One holds search results, other has some random text as content for the body. ListView
(search result) is placed inside an Align Object and alignment property is set to Alignment.topCenter. This ensures that List appears at the top, just below the AppBar
.
Updated the Post (accepted answer) mentioned in the comments for a complete a demo.
As explained above:
@override
Widget build(BuildContext context) {
return new Scaffold(
key: key,
appBar: buildBar(context),
body: new Stack(
children: <Widget>[
new Container(
height: 300.0,
padding: EdgeInsets.all(10.0),
child: new DefaultTabController(length: 5, child: mainTabView),
),
displaySearchResults(),
],
));
}
Widget displaySearchResults() {
if (_IsSearching) {
return new Align(
alignment: Alignment.topCenter,
//heightFactor: 0.0,
child: searchList());
} else {
return new Align(alignment: Alignment.topCenter, child: new Container());
}
}
Complete demo
class SearchList extends StatefulWidget {
SearchList({Key key, this.name}) : super(key: key);
final String name;
@override
_SearchListState createState() => new _SearchListState();
}
class _SearchListState extends State<SearchList> {
Widget appBarTitle = new Text(
"",
style: new TextStyle(color: Colors.white),
);
Icon actionIcon = new Icon(
Icons.search,
color: Colors.white,
);
final key = new GlobalKey<ScaffoldState>();
final TextEditingController _searchQuery = new TextEditingController();
List<SearchResult> _list;
bool _IsSearching;
String _searchText = "";
String selectedSearchValue = "";
_SearchListState() {
_searchQuery.addListener(() {
if (_searchQuery.text.isEmpty) {
setState(() {
_IsSearching = false;
_searchText = "";
});
} else {
setState(() {
_IsSearching = true;
_searchText = _searchQuery.text;
});
}
});
}
@override
void initState() {
super.initState();
_IsSearching = false;
createSearchResultList();
}
void createSearchResultList() {
_list = <SearchResult>[
new SearchResult(name: 'Google'),
new SearchResult(name: 'IOS'),
new SearchResult(name: 'IOS2'),
new SearchResult(name: 'Android'),
new SearchResult(name: 'Dart'),
new SearchResult(name: 'Flutter'),
new SearchResult(name: 'Python'),
new SearchResult(name: 'React'),
new SearchResult(name: 'Xamarin'),
new SearchResult(name: 'Kotlin'),
new SearchResult(name: 'Java'),
new SearchResult(name: 'RxAndroid'),
];
}
@override
Widget build(BuildContext context) {
return new Scaffold(
key: key,
appBar: buildBar(context),
body: new Stack(
children: <Widget>[
new Container(
height: 300.0,
padding: EdgeInsets.all(10.0),
child: new Container(
child: ListView(
children: <Widget>[
new Text("Hello World!"),
new Text("Hello World!"),
new Text("Hello World!"),
new Text("Hello World!"),
new Text("Hello World!"),
new Text("Hello World!"),
new Text("Hello World!"),
new Text("Hello World!"),
new Text("Hello World!"),
new Text("Hello World!"),
new Text("Hello World!"),
new Text("Hello World!"),
new Text("Hello World!"),
],
),
),
),
displaySearchResults(),
],
));
}
Widget displaySearchResults() {
if (_IsSearching) {
return new Align(
alignment: Alignment.topCenter,
child: searchList());
} else {
return new Align(alignment: Alignment.topCenter, child: new Container());
}
}
ListView searchList() {
List<SearchResult> results = _buildSearchList();
return ListView.builder(
itemCount: _buildSearchList().isEmpty == null ? 0 : results.length,
itemBuilder: (context, int index) {
return Container(
decoration: new BoxDecoration(
color: Colors.grey[100],
border: new Border(
bottom: new BorderSide(
color: Colors.grey,
width: 0.5
)
)
),
child: ListTile(
onTap: (){},
title: Text(results.elementAt(index).name,
style: new TextStyle(fontSize: 18.0)),
),
);
},
);
}
List<SearchResult> _buildList() {
return _list.map((result) => new SearchResult(name: result.name)).toList();
}
List<SearchResult> _buildSearchList() {
if (_searchText.isEmpty) {
return _list.map((result) => new SearchResult(name: result.name)).toList();
} else {
List<SearchResult> _searchList = List();
for (int i = 0; i < _list.length; i++) {
SearchResult result = _list.elementAt(i);
if ((result.name).toLowerCase().contains(_searchText.toLowerCase())) {
_searchList.add(result);
}
}
return _searchList
.map((result) => new SearchResult(name: result.name))
.toList();
}
}
Widget buildBar(BuildContext context) {
return new AppBar(
centerTitle: true,
title: appBarTitle,
actions: <Widget>[
new IconButton(
icon: actionIcon,
onPressed: () {
_displayTextField();
},
),
// new IconButton(icon: new Icon(Icons.more), onPressed: _IsSearching ? _showDialog(context, _buildSearchList()) : _showDialog(context,_buildList()))
],
);
}
String selectedPopupRoute = "My Home";
final List<String> popupRoutes = <String>[
"My Home",
"Favorite Room 1",
"Favorite Room 2"
];
void _displayTextField() {
setState(() {
if (this.actionIcon.icon == Icons.search) {
this.actionIcon = new Icon(
Icons.close,
color: Colors.white,
);
this.appBarTitle = new TextField(
autofocus: true,
controller: _searchQuery,
style: new TextStyle(
color: Colors.white,
),
);
_handleSearchStart();
} else {
_handleSearchEnd();
}
});
}
void _handleSearchStart() {
setState(() {
_IsSearching = true;
});
}
void _handleSearchEnd() {
setState(() {
this.actionIcon = new Icon(
Icons.search,
color: Colors.white,
);
this.appBarTitle = new Text(
"",
style: new TextStyle(color: Colors.white),
);
_IsSearching = false;
_searchQuery.clear();
});
}
}
this plugin will helpful for you,loader_search_bar
Flutter widget integrating search field feature into app bar, allowing to receive query change callbacks and automatically load new data set into ListView. It replaces standard AppBar widget and needs to be placed underneath Scaffold element in the widget tree to work properly.
Getting started To start using SearchBar insert it in place of an AppBar element in the Scaffold widget. Regardless of the use case, defaultBar named argument has to be specified, which basically is a widget that will be displayed whenever SearchBar is not in activated state:
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: SearchBar(
defaultBar: AppBar(
leading: IconButton(
icon: Icon(Icons.menu),
onPressed: _openDrawer,
),
title: Text('Default app bar title'),
),
...
),
body: _body,
drawer: _drawer,
);
}
Optional attributes
Query callbacks
To get notified about user input specify onQueryChanged and/or onQuerySubmitted callback functions that receive current query string as an argument:
appBar: SearchBar(
...
onQueryChanged: (query) => _handleQueryChanged(context, query),
onQuerySubmitted: (query) => _handleQuerySubmitted(context, query),
),
QuerySetLoader
By passing QuerySetLoader object as an argument one can additionally benefit from search results being automatically built as ListView widget whenever search query changes:
appBar: SearchBar(
...
loader: QuerySetLoader<Item>(
querySetCall: _getItemListForQuery,
itemBuilder: _buildItemWidget,
loadOnEachChange: true,
animateChanges: true,
),
),
List<Item> _getItemListForQuery(String query) { ... }
Widget _buildItemWidget(Item item) { ... }
SearchItem
Specifying this parameter allows to customize how search item should be built and positioned in app bar. It can be either action or menu widget. No matter which of these two is picked, two constructor arguments can be passed:
SearchItem.action
appBar: SearchBar(
// ...
searchItem: SearchItem.action(
builder: (_) => Padding(
padding: EdgeInsets.all(12.0),
child: Icon(
Icons.find_in_page,
color: Colors.indigoAccent,
),
),
gravity: SearchItemGravity.exactly(1),
),
)
SearchItem.menu
appBar: SearchBar(
// ...
searchItem: SearchItem.menu(
builder: (_) => PopupMenuItem(
child: Text("Search 🔍"),
value: "search",
),
gravity: SearchItemGravity.end,
),
)
Also, bear in mind that SearchBar will prevent built item widget from receiving tap events and will begin search action rather than that.
hope it will help you.
It is actually very simple. you can refer above answers for details. Let's follow these steps:
void initState() {
filteredList.addAll(autoList);
}
Create a custom search bar widget with a TextField in it
we will be getting a 'value' i.e. the text entered from this Textfield: eg. TextFiled(onchange(value){})
Assuming that we have strings in our autoList, write:
filteredList.removeWhere((i) => i.contains(value.toString())==false);
The complete TextField widget will look like:
TextField(
onChanged: (value) {
setState(() {
filteredList.clear(); //for the next time that we search we want the list to be unfilterted
filteredList.addAll(autoList); //getting list to original state
//removing items that do not contain the entered Text
filteredList.removeWhere((i) => i.contains(value.toString())==false);
//following is just a bool parameter to keep track of lists
searched=!searched;
});
},
controller: editingController,
decoration: InputDecoration(
border: InputBorder.none,
labelText: "Search for the filtered list",
prefixIcon: Icon(Icons.search),
),
),
Now, along the search bar, we just have to display filteredList with ListViewBuilder. done :)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With