Reputation: 365
There are a lot of tutorials but rather than help me to move forward, I get lost in all possible options or I don't know how to improve the code (I would like to use an application that displays a list that use more than only the name of three fruits or three cities ?)
I found tutorials to create a nice SearchBar with the ability to display the result based on the first letters typed.
I don't understand how to edit the tutorial with a data list that includes a title associated with the content. I don't understand how to display the result if the first letter is lowercase or uppercase. Would it be possible to help me to make a simple basic code that could serve everyone including beginners like me?
DataList.dart
List<ListWords> listWords = [
ListWords('oneWord', 'OneWord definition'),
ListWords('twoWord', 'TwoWord definition.'),
ListWords('TreeWord', 'TreeWord definition'),
];
class ListWords {
String titlelist;
String definitionlist;
ListWords(String titlelist, String definitionlist) {
this.titlelist = titlelist;
this.definitionlist = definitionlist;
}
}
Searchbar.dart
import 'package:flutter/material.dart';
import 'package:test_searchbar/DataList.dart';
class SearchBar extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Search App'),
actions: <Widget>[
IconButton(icon: Icon(Icons.search),
onPressed: () {
showSearch(context: context, delegate: DataSearch(listWords));
})
],
),
drawer: Drawer(),
);
}
}
class DataSearch extends SearchDelegate<String> {
final List<ListWords> listWords;
DataSearch(this.listWords);
@override
List<Widget> buildActions(BuildContext context) {
//Actions for app bar
return [IconButton(icon: Icon(Icons.clear), onPressed: () {
query = '';
})];
}
@override
Widget buildLeading(BuildContext context) {
//leading icon on the left of the app bar
return IconButton(
icon: AnimatedIcon(icon: AnimatedIcons.menu_arrow,
progress: transitionAnimation,
),
onPressed: () {
close(context, null);
});
}
@override
Widget buildResults(BuildContext context) {
// show some result based on the selection
return Center(
child: Text(query),
);
}
@override
Widget buildSuggestions(BuildContext context) {
// show when someone searches for something
final suggestionList = query.isEmpty
? listWords
: listWords.where((p) => p.startsWith(query)).toList();
return ListView.builder(itemBuilder: (context, index) => ListTile(
onTap: () {
showResults(context);
},
trailing: Icon(Icons.remove_red_eye),
title: RichText(
text: TextSpan(
text: suggestionList[index].titlelist.substring(0, query.length),
style: TextStyle(
color: Colors.red, fontWeight: FontWeight.bold),
children: [
TextSpan(
text: suggestionList[index].titlelist.substring(query.length),
style: TextStyle(color: Colors.grey))
]),
),
),
itemCount: suggestionList.length,
);
}
}
Upvotes: 25
Views: 85910
Reputation: 7682
Here is a complete working example:
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key}) : super(key: key);
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final TextEditingController _searchController = TextEditingController();
final List<String> _data = [
'Apple',
'Banana',
'Cherry',
'Date',
'Fig',
'Grape',
'Lemon',
'Mango',
'Orange',
'Papaya',
'Peach',
'Plum',
'Raspberry',
'Strawberry',
'Watermelon',
];
List<String> _filteredData = [];
bool _isLoading = false;
@override
void initState() {
super.initState();
_filteredData = _data;
_searchController.addListener(_performSearch);
}
@override
void dispose() {
_searchController.dispose();
super.dispose();
}
Future<void> _performSearch() async {
setState(() {
_isLoading = true;
});
//Simulates waiting for an API call
await Future.delayed(const Duration(milliseconds: 1000));
setState(() {
_filteredData = _data
.where((element) => element
.toLowerCase()
.contains(_searchController.text.toLowerCase()))
.toList();
_isLoading = false;
});
}
@override
Widget build(BuildContext context) => Scaffold(
appBar: AppBar(
flexibleSpace: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Colors.deepPurple, Colors.purple.shade300],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
),
),
title: TextField(
controller: _searchController,
style: const TextStyle(color: Colors.white),
cursorColor: Colors.white,
decoration: const InputDecoration(
hintText: 'Search...',
hintStyle: TextStyle(color: Colors.white54),
border: InputBorder.none,
),
),
),
body: _isLoading
? const Center(
child: CircularProgressIndicator(color: Colors.white),
)
: ListView.builder(
itemCount: _filteredData.length,
itemBuilder: (context, index) => ListTile(
title: Text(
_filteredData[index],
style: const TextStyle(color: Colors.white),
),
),
),
backgroundColor: Colors.deepPurple.shade900,
);
}
You can read more about the example here.
Upvotes: 0
Reputation: 726
There is a ready to use widget for this:
appBar: AppBarWithSearchSwitch(
onChanged: (text) {
searchText.value = text;
}, // or use: onSubmitted: (text) => searchText.value = text,
appBarBuilder: (context) {
return AppBar(
title: Text('Example '),
actions: [
AppBarSearchButton(), // button to activate search
],
Upvotes: 1
Reputation: 97
Scaffold(
appBar: AppBar(
backgroundColor: Color.fromRGBO(93, 25, 72, 1),
toolbarHeight: 60.0,
title: TextField(
cursorColor: Colors.white,
decoration: InputDecoration(
hintText: " Search...",
border: InputBorder.none,
suffixIcon: IconButton(
icon: Icon(Icons.search),
color: Color.fromRGBO(93, 25, 72, 1),
onPressed: () {},
)),
style: TextStyle(color: Colors.white, fontSize: 15.0),
),
),
);
Upvotes: 1
Reputation: 7150
To create a search appbar, you will need a stateful widget with the following code,
Inside your State class,
TextEditingController _searchQueryController = TextEditingController();
bool _isSearching = false;
String searchQuery = "Search query";
Inside Scaffold, your appbar should be like,
appBar: AppBar(
leading: _isSearching ? const BackButton() : Container(),
title: _isSearching ? _buildSearchField() : _buildTitle(context),
actions: _buildActions(),
),
Define the required following methods for displaying and managing searchbar,
Widget _buildSearchField() {
return TextField(
controller: _searchQueryController,
autofocus: true,
decoration: InputDecoration(
hintText: "Search Data...",
border: InputBorder.none,
hintStyle: TextStyle(color: Colors.white30),
),
style: TextStyle(color: Colors.white, fontSize: 16.0),
onChanged: (query) => updateSearchQuery(query),
);
}
List<Widget> _buildActions() {
if (_isSearching) {
return <Widget>[
IconButton(
icon: const Icon(Icons.clear),
onPressed: () {
if (_searchQueryController == null ||
_searchQueryController.text.isEmpty) {
Navigator.pop(context);
return;
}
_clearSearchQuery();
},
),
];
}
return <Widget>[
IconButton(
icon: const Icon(Icons.search),
onPressed: _startSearch,
),
];
}
void _startSearch() {
ModalRoute.of(context)
.addLocalHistoryEntry(LocalHistoryEntry(onRemove: _stopSearching));
setState(() {
_isSearching = true;
});
}
void updateSearchQuery(String newQuery) {
setState(() {
searchQuery = newQuery;
});
}
void _stopSearching() {
_clearSearchQuery();
setState(() {
_isSearching = false;
});
}
void _clearSearchQuery() {
setState(() {
_searchQueryController.clear();
updateSearchQuery("");
});
}
This is the best way to implement an app searchbar in any flutter screen.
Upvotes: 45
Reputation: 365
Finally, I managed to do this. This is a good starting point for the Search Show in a list. Does this are correct?
DataList.dart
List<ListWords> listWords = [
ListWords('oneWord', 'OneWord definition'),
ListWords('twoWord', 'TwoWord definition.'),
ListWords('TreeWord', 'TreeWord definition'),
];
class ListWords {
String titlelist;
String definitionlist;
ListWords(String titlelist, String definitionlist) {
this.titlelist = titlelist;
this.definitionlist = definitionlist;
}
}
SearchBar.dart
import 'dart:core';
import 'package:flutter/material.dart';
import 'package:test_searchbar/DataList.dart';
import 'package:test_searchbar/detail.dart';
class SearchBar extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Search App'),
actions: <Widget>[
IconButton(icon: Icon(Icons.search),
onPressed: () {
showSearch(context: context, delegate: DataSearch(listWords));
})
],
),
body: Center(
child: Text('default content')
),
drawer: Drawer(),
);
}
}
class DataSearch extends SearchDelegate<String> {
final List<ListWords> listWords;
DataSearch(this.listWords);
@override
List<Widget> buildActions(BuildContext context) {
//Actions for app bar
return [IconButton(icon: Icon(Icons.clear), onPressed: () {
query = '';
})];
}
@override
Widget buildLeading(BuildContext context) {
//leading icon on the left of the app bar
return IconButton(
icon: AnimatedIcon(icon: AnimatedIcons.menu_arrow,
progress: transitionAnimation,
),
onPressed: () {
close(context, null);
});
}
@override
Widget buildResults(BuildContext context) {
// show some result based on the selection
final suggestionList = listWords;
return ListView.builder(itemBuilder: (context, index) => ListTile(
title: Text(listWords[index].titlelist),
subtitle: Text(listWords[index].definitionlist),
),
itemCount: suggestionList.length,
);
}
@override
Widget buildSuggestions(BuildContext context) {
// show when someone searches for something
final suggestionList = query.isEmpty
? listWords
: listWords.where((p) => p.titlelist.contains(RegExp(query, caseSensitive: false))).toList();
return ListView.builder(itemBuilder: (context, index) => ListTile(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Detail(listWordsDetail: suggestionList[index]),
),
);
},
trailing: Icon(Icons.remove_red_eye),
title: RichText(
text: TextSpan(
text: suggestionList[index].titlelist.substring(0, query.length),
style: TextStyle(
color: Colors.red, fontWeight: FontWeight.bold),
children: [
TextSpan(
text: suggestionList[index].titlelist.substring(query.length),
style: TextStyle(color: Colors.grey)),
]),
),
),
itemCount: suggestionList.length,
);
}
}
detail.dart
import 'package:flutter/material.dart';
import 'package:test_searchbar/DataList.dart';
class Detail extends StatelessWidget {
final ListWords listWordsDetail;
Detail({Key key, @required this.listWordsDetail}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
brightness: Brightness.dark,
title: const Text('Détail', style: TextStyle(color: Colors.white)),
iconTheme: IconThemeData(color: Colors.white),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(listWordsDetail.titlelist +' (on detail page)'),
Text(listWordsDetail.definitionlist),
],
),
)
);
}
}
It would be best if the return from the detail page opens the Searchbar page with the default content and the closed searchbar ...
Upvotes: 1