Flutter Searchview and Listview tutorial examples.
In this piece we want to look at some of the best and easiest Flutter SearchView examples.
Example 1 - Search Filter ListView of Cards
We see how to search/filter a listview in flutter using a searchview. That so called searchview is actually a custom textfield. We will use a TextEditingController to notify us of text changeson our textfield. Thus this allows us easily search our data.
That data is actually bound from a simple list. And in fact we will maintain two lists:
- First List - The actual data source. This never changes.
- Second List - This will hold the filter results. For example if you search and have 5 results from a list of a hundred, then we hold those 5 results in this second list.
The search itself is rather simple. We simply use the contains()
method of the string
class. However we have to make sure we have case consistency, such that for example our query is in lowercase then the data also has to be in lowercase.
Demo
Here are the demo for this project:
Video Tutorial
If you prefer a video tutorial for this you can watch it here in our YouTube Channel:
(a). pubspec.yaml
We are not using any third party library.
Instead here we will have the name and description of app.
name: mr_searchview
description: Flutter SearchView example project.
dependencies:
flutter:
sdk: flutter
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^0.1.2
dev_dependencies:
flutter_test:
sdk: flutter
(b). main.dart
Here's our full main.dart
code.
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
//Our MyApp class. Represents our application
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: "ListView SearchView",
home: new Home(),
theme: ThemeData(primaryColor: Colors.orange),
);
}
}
//Represents the Homepage widget
class Home extends StatefulWidget {
//<code>createState()
will create the mutable state for this widget at
//a given location in the tree.
@override
_HomeState createState() => _HomeState();
}
//Our Home state, the logic and internal state for a StatefulWidget.
class _HomeState extends State<Home> {
//A controller for an editable text field.
//Whenever the user modifies a text field with an associated
//TextEditingController, the text field updates value and the
//controller notifies its listeners.
var _searchview = new TextEditingController();
bool _firstSearch = true;
String _query = "";
List<String> _nebulae;
List<String> _filterList;
@override
void initState() {
super.initState();
_nebulae = new List<String>();
_nebulae = [
"Orion",
"Boomerang",
"Cat's Eye",
"Pelican",
"Ghost Head",
"Witch Head",
"Snake",
"Ant",
"Bernad 68",
"Flame",
"Eagle",
"Horse Head",
"Elephant's Trunk",
"Butterfly"
];
_nebulae.sort();
}
_HomeState() {
//Register a closure to be called when the object changes.
_searchview.addListener(() {
if (_searchview.text.isEmpty) {
//Notify the framework that the internal state of this object has changed.
setState(() {
_firstSearch = true;
_query = "";
});
} else {
setState(() {
_firstSearch = false;
_query = _searchview.text;
});
}
});
}
//Build our Home widget
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: new AppBar(
title: new Text("SearchView ListView"),
),
body: new Container(
margin: EdgeInsets.only(left: 10.0, right: 10.0, top: 10.0),
child: new Column(
children: <Widget>[
_createSearchView(),
_firstSearch ? _createListView() : _performSearch()
],
),
),
);
}
//Create a SearchView
Widget _createSearchView() {
return new Container(
decoration: BoxDecoration(border: Border.all(width: 1.0)),
child: new TextField(
controller: _searchview,
decoration: InputDecoration(
hintText: "Search",
hintStyle: new TextStyle(color: Colors.grey[300]),
),
textAlign: TextAlign.center,
),
);
}
//Create a ListView widget
Widget _createListView() {
return new Flexible(
child: new ListView.builder(
itemCount: _nebulae.length,
itemBuilder: (BuildContext context, int index) {
return new Card(
color: Colors.white,
elevation: 5.0,
child: new Container(
margin: EdgeInsets.all(15.0),
child: new Text("${_nebulae[index]}"),
),
);
}),
);
}
//Perform actual search
Widget _performSearch() {
_filterList = new List<String>();
for (int i = 0; i < _nebulae.length; i++) {
var item = _nebulae[i];
if (item.toLowerCase().contains(_query.toLowerCase())) {
_filterList.add(item);
}
}
return _createFilteredListView();
}
//Create the Filtered ListView
Widget _createFilteredListView() {
return new Flexible(
child: new ListView.builder(
itemCount: _filterList.length,
itemBuilder: (BuildContext context, int index) {
return new Card(
color: Colors.white,
elevation: 5.0,
child: new Container(
margin: EdgeInsets.all(15.0),
child: new Text("${_filterList[index]}"),
),
);
}),
);
}
}
How to Download and Run.
Just copy this code into main.dart
file. There is no setup required.
Example 2 - Search Filter ListView From AppBar/Toolbar
This is the second flutter searchview example. It's also easy to understand and will help implement search filter in flutter using Dart Programming of course. This example also doesn't require any setup or dependencies. This example will involve rendering a searchview in the toolbar or appBar of our application.
Let's start.
Demo
Here is demo.
Flutter AppBar SearchView
(a). search_list.dart
This file will define us a stateful widget to represent our searchable listview.'
Add Imports
Start by importing material.dart
:
import 'package:flutter/material.dart';
Create Stateful Widget
Then create the widget by extending the StatefulWidget:
class SearchList extends StatefulWidget {
and defining the constructor:
SearchList({ Key key }) : super(key: key);
then finally overriding the createState()
method:
@override
_SearchListState createState() => new _SearchListState();
}
Create State class
Start by extending the State class:
class _SearchListState extends State<SearchList>
{
Then define instance fields:
Widget appBarTitle = new Text("Search Sample", 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<String> _list;
bool _IsSearching;
String _searchText = "";
The instance fields as you can see include the appBar title, icon, TextEditingController etc.
In the constructor attach a listener to the TextEditingController. This allows us to be notified of text change events in the editing fields as the user types:
_SearchListState() {
_searchQuery.addListener(() {
if (_searchQuery.text.isEmpty) {
setState(() {
_IsSearching = false;
_searchText = "";
});
}
else {
setState(() {
_IsSearching = true;
_searchText = _searchQuery.text;
});
}
});
}
Now override the initState()
method:
@override
void initState() {
super.initState();
_IsSearching = false;
init();
}
Add List of items to act as the data source:
void init() {
_list = List();
_list.add("Google");
_list.add("IOS");
_list.add("Andorid");
_list.add("Dart");
_list.add("Flutter");
_list.add("Python");
_list.add("React");
_list.add("Xamarin");
_list.add("Kotlin");
_list.add("Java");
_list.add("RxAndroid");
}
Override the build()
method of this state class:
@override
Widget build(BuildContext context) {
return new Scaffold(
key: key,
appBar: buildBar(context),
body: new ListView(
padding: new EdgeInsets.symmetric(vertical: 8.0),
children: _IsSearching ? _buildSearchList() : _buildList(),
),
);
}
In it you can see we are building our widget by specifying the appBar as well as the body which in this case will contain a ListView.
Then two helper methods returning List of data:
List<ChildItem> _buildList() {
return _list.map((contact) => new ChildItem(contact)).toList();
}
List<ChildItem> _buildSearchList() {
if (_searchText.isEmpty) {
return _list.map((contact) => new ChildItem(contact))
.toList();
}
else {
List<String> _searchList = List();
for (int i = 0; i < _list.length; i++) {
String name = _list.elementAt(i);
if (name.toLowerCase().contains(_searchText.toLowerCase())) {
_searchList.add(name);
}
}
return _searchList.map((contact) => new ChildItem(contact))
.toList();
}
}
Then a helper method to help in constructing the AppBar widget:
Widget buildBar(BuildContext context) {
return new AppBar(
centerTitle: true,
title: appBarTitle,
actions: <Widget>[
new IconButton(icon: actionIcon, onPressed: () {
setState(() {
if (this.actionIcon.icon == Icons.search) {
this.actionIcon = new Icon(Icons.close, color: Colors.white,);
this.appBarTitle = new TextField(
controller: _searchQuery,
style: new TextStyle(
color: Colors.white,
),
decoration: new InputDecoration(
prefixIcon: new Icon(Icons.search, color: Colors.white),
hintText: "Search...",
hintStyle: new TextStyle(color: Colors.white)
),
);
_handleSearchStart();
}
else {
_handleSearchEnd();
}
});
},),
]
);
}
That appBar widget will have a searchview in it as you can see in the above method.
Then lastly for this state class, create methods to handle search start and search end:
void _handleSearchStart() {
setState(() {
_IsSearching = true;
});
}
void _handleSearchEnd() {
setState(() {
this.actionIcon = new Icon(Icons.search, color: Colors.white,);
this.appBarTitle =
new Text("Search Sample", style: new TextStyle(color: Colors.white),);
_IsSearching = false;
_searchQuery.clear();
});
}
}
That is the end of the State class.
Now below it create another class called childItem
. It's also a widget representing a single ListView item:
class ChildItem extends StatelessWidget {
final String name;
ChildItem(this.name);
@override
Widget build(BuildContext context) {
return new ListTile(title: new Text(this.name));
}
}
(b). main.dart
Come in the main file and add the following code:
import 'package:flutter/material.dart';
import 'package:flutter_search_app/search_list.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Search',
debugShowCheckedModeBanner: false,
theme: new ThemeData(
brightness: Brightness.light,
primarySwatch:Colors.yellow,
primaryColor: Color(0xFFFFBB54),
accentColor: Color(0xFFECEFF1),
),
home: new SearchList(),
);
}
}
That's it.
Special Thanks to @MageshPandian20 for this wonderful example.
Have a good day.