Flutter search bar with autocomplete - flutter

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();
});
}
}

It is actually very simple. you can refer above answers for details. Let's follow these steps:
Create a list of items we want to have in the autofill menu, lets name it autoList
Create one more emptyList named filteredList
Add all the values of autoList to filterList
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 :)

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
searchHint - hint string being displayed until user inputs any text,
initialQuery - query value displayed for the first time in search field,
iconified - boolean value indicating way of representing non-activated SearchBar:
true if widget should be showed as an action item in defaultBar,
false if widget should be merged with defaultBar (only leading icon of the default widget and search input field are displayed in such case),
autofocus - boolean value determining if search text field should get focus whenever it becomes visible,
autoActive - ,
attrs - SearchBarAttrs class instance allowing to specify part of exact values used during widget building (e.g. search bar colors, text size, border radius),
controller - SearchBarController object that provides a way of interacing with current state of the widget,
searchItem - defining how to build and position search item widget in app bar,
overlayStyle - status bar overlay brightness applied when widget is activated.
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) { ... }
querySetCall - function transforming search query into list of items being then rendered in ListView (required),
itemBuilder - function creating Widget object for received item, called during ListView building for each element of the results set (required),
loadOnEachChange - boolean value indicating whether querySetCall should be triggered on each query change; if false query set is loaded once user submits query,
animateChanges - determines whether ListView's insert and remove operations should be animated.
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:
builder - function receiving current BuildContext and returning Widget for action or PopupMenuItem for menu item,
gravity - can be one of SearchItemGravity values: start, end or exactly. If no arguments are passed, SearchBar will create default item which is search action icon with start gravity.
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.

import 'package:flutter/material.dart';
class SearchText extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Searchable Text"),
actions: <Widget>[
IconButton(
icon: Icon(Icons.search),
onPressed: () {
showSearch(
context: context,
delegate: DataSearch(),
);
})
],
),
drawer: Drawer(),
);
}
}
class DataSearch extends SearchDelegate<String> {
final cities = ['Ankara', 'İzmir', 'İstanbul', 'Samsun', 'Sakarya'];
var recentCities = ['Ankara'];
#override
List<Widget> buildActions(BuildContext context) {
return [
IconButton(
icon: Icon(Icons.clear),
onPressed: () {
query = "";
})
];
}
#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 Center(
child: Container(
width: 100,
height: 100,
child: Card(
color: Colors.red,
child: Center(child: Text(query)),
),
),
);
}
#override
Widget buildSuggestions(BuildContext context) {
final suggestionList = query.isEmpty
? recentCities
: cities.where((p) => p.startsWith(query)).toList();
return ListView.builder(
itemBuilder: (context, index) => ListTile(
onTap: () {
showResults(context);
},
leading: Icon(Icons.location_city),
title: RichText(
text: TextSpan(
text: suggestionList[index].substring(0, query.length),
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold,
),
children: [
TextSpan(
text: suggestionList[index].substring(query.length),
),
],
),
),
),
itemCount: suggestionList.length,
);
}
}

Related

Keep dropdown open when active checkbox

I have a code that is responsible for filtering by certain categories (I shortened it for ease of reading). When opening the filter window, the user sees these category names ('Select a brand', 'Select a operation system', 'Select a color' etc).
Next, the user can open the category (initially, the dropdown list is in the closed position.), and select the parameters from the drop-down list (and click the apply button). The next time you open the filter window, the checkboxes in front of the parameters remain, but the drop-down list collapses.
Tell me how to do it: if in any category there are options marked with a checkmark, so that the drop-down list will be open the next time the window with filters is opened.
class FilterDialog extends StatefulWidget {
final void Function(Map<String, List<String>?>) onApplyFilters;
final Map<String, List<String>?> initialState;
const FilterDialog({
Key? key,
required this.onApplyFilters,
this.initialState = const {},
}) : super(key: key);
#override
State<FilterDialog> createState() => _FilterDialogState();
}
class _FilterDialogState extends State<FilterDialog> {
// Temporary storage of filters.
Map<String, List<String>?> filters = {};
bool needRefresh = false;
// Variable for the ability to hide all elements of filtering by any parameter.
bool isClickedBrand = false;
List manufacturer = [];
#override
void initState() {
super.initState();
filters = widget.initialState;
}
// A function to be able to select an element to filter.
void _handleCheckFilter(bool checked, String key, String value) {
final currentFilters = filters[key] ?? [];
if (checked) {
currentFilters.add(value);
} else {
currentFilters.remove(value);
}
setState(() {
filters[key] = currentFilters;
});
}
// Building a dialog box with filters.
#override
Widget build(BuildContext context) {
return SimpleDialog(
// Window title.
title: const Text('Filters',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 25,
fontWeight: FontWeight.w600,
)),
contentPadding: const EdgeInsets.all(16),
// Defining parameters for filtering.
children: [
Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// Here and in subsequent Column, there will be a definition of parameters for filtering,
// a title, the ability to hide/show the items of list
Column(children: [
InkWell(
onTap: () async {
manufacturer = await getManufacturerOptions();
setState(() {
isClickedBrand = !isClickedBrand;
});
},
child: Row(children: [
Text('Select a brand'.toString(),
style: const TextStyle(
fontSize: 18,
)),
const Spacer(),
isClickedBrand
? const Icon(Icons.arrow_circle_up)
: const Icon(Icons.arrow_circle_down)
])),
!isClickedBrand
? Container()
: Column(
children: manufacturer
.map(
(el) => CustomCheckboxTile(
value: filters['manufacturer']?.contains(el) ??
false,
label: el,
onChange: (check) =>
_handleCheckFilter(check, 'manufacturer', el),
),
)
.toList())
]),
const SizedBox(
height: 5,
),
// Building a button to apply parameters.
const SizedBox(
height: 10,
),
ElevatedButton(
onPressed: () {
Navigator.of(context).pop();
widget.onApplyFilters(filters);
needRefresh = true;
},
child:
const Text('APPLY', style: TextStyle(color: Colors.black)),
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(Colors.grey),
)),
// Building a button to reset parameters.
const SizedBox(
height: 5,
),
ElevatedButton(
onPressed: () async {
setState(() {
filters.clear();
});
widget.onApplyFilters(filters);
},
child: const Text('RESET FILTERS',
style: TextStyle(color: Colors.black)),
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(Colors.grey),
)),
],
),
],
);
}
}
For example: the user clicks on the filter box, selects the brands to search for, and clicks the apply button. My task is that the next time the user opens the filter window, the categories with active checkboxes (in this example, the brand) are in an expanded state
The concept is, you need to check filter data with while opening dialog, To simplify the process I am using ExpansionTile. You can check this demo and customize the behavior and look.
Run on dartPad, Click fab to open dialog and touch outside the dialog to close this.
class ExTExpample extends StatefulWidget {
ExTExpample({Key? key}) : super(key: key);
#override
State<ExTExpample> createState() => _ExTExpampleState();
}
class _ExTExpampleState extends State<ExTExpample> {
// you can use map or model class or both,
List<String> filter_data = [];
List<String> brands = ["Apple", "SamSung"];
List<String> os = ["iOS", "Android"];
_showFilter() async {
await showDialog(
context: context,
builder: (c) {
// you can replace [AlertDialog]
return AlertDialog(
content: StatefulBuilder(
builder: (context, setSBState) => SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
ExpansionTile(
title: const Text("Brand"),
/// check any of its's item is checked or not
initiallyExpanded: () {
// you can do different aproach
for (final f in brands) {
if (filter_data.contains(f)) return true;
}
return false;
}(),
children: [
...brands.map(
(brandName) => CheckboxListTile(
value: filter_data.contains(brandName),
title: Text(brandName),
onChanged: (v) {
if (filter_data.contains(brandName)) {
filter_data.remove(brandName);
} else {
filter_data.add(brandName);
}
setSBState(() {});
//you need to reflect the main ui, also call `setState((){})`
},
),
),
],
),
ExpansionTile(
title: const Text("select OS"),
/// check any of its's item is checked or not
initiallyExpanded: () {
// you can do different aproach
for (final f in os) {
if (filter_data.contains(f)) return true;
}
return false;
}(),
children: [
...os.map(
(osName) => CheckboxListTile(
value: filter_data.contains(osName),
title: Text(osName),
onChanged: (v) {
if (filter_data.contains(osName)) {
filter_data.remove(osName);
} else {
filter_data.add(osName);
}
setSBState(() {});
//you need to reflect the main ui, also call `setState((){})`
},
),
),
],
),
],
),
),
),
);
},
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: FloatingActionButton(
onPressed: () {
_showFilter();
},
),
),
);
}
}
Whenever you open filter the isClickedBrand is False so it won't showed you a list. So the solution is :
After selecting option from list, change the state of isClickedBrand state. I mean if it's true then it will show the list otherwise show container.
Hope you get my point.

How to implement a Flutter Search App Bar

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,
);
}
}
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.
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 ...
There is a ready to use widget for this:
AppBar with search switch on pub.dev:
https://pub.dev/packages/app_bar_with_search_switch
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
],
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),
),
),
);

how to filter json from dropdown in flutter

enter code herehey all of master , i have code for filter data on api json, i want my user can select specific teacher by specific locatioin on drop down. the search by name are already work, but the dropdown i don't know how to implement it, to take effect on my json api slection.
here is my code
import 'package:flutter/material.dart';
void main() {
runApp(new MaterialApp(
title: "Para Dai",
home: new DropDown(),
));
}
class DropDown extends StatefulWidget {
DropDown() : super();
// end
final String title = "DropDown Demo";
#override
DropDownState createState() => DropDownState();
}
class Province {
int id;
String name;
Province(this.id, this.name);
static List<Province> getProvinceList() {
return <Province>[
Province(1, 'Central Java'),
Province(2, 'East kalimantan'),
Province(3, 'East java'),
Province(4, 'Bali'),
Province(5, 'Borneo'),
];
}
}
// ADD THIS
class District {
int id;
String name;
District(this.id, this.name);
static List<District> getDistrictList() {
return <District>[
District(1, 'Demak'),
District(2, 'Solo'),
District(3, 'Sidoarjo'),
District(4, 'Bandung'),
];
}
}
class DropDownState extends State<DropDown> {
String finalUrl = '';
List<Province> _provinces = Province.getProvinceList();
List<DropdownMenuItem<Province>> _dropdownMenuItems;
Province _selectedProvince;
// ADD THIS
List<District> _disctricts = District.getDistrictList();
List<DropdownMenuItem<District>> _dropdownMenuDistricts;
District _selectedDistrict;
#override
void initState() {
_dropdownMenuItems = buildDropdownMenuItems(_provinces);
_dropdownMenuDistricts = buildDropdownDistricts(_disctricts); // Add this
_selectedProvince = _dropdownMenuItems[0].value;
_selectedDistrict = _dropdownMenuDistricts[0].value; // Add this
super.initState();
}
List<DropdownMenuItem<Province>> buildDropdownMenuItems(List provinceses) {
List<DropdownMenuItem<Province>> items = List();
for (var province in provinceses) {
items.add(
DropdownMenuItem(
value: province,
child: Text(province.name),
),
);
}
return items;
}
// ADD THIS
List<DropdownMenuItem<District>> buildDropdownDistricts(
List<District> districts) {
List<DropdownMenuItem<District>> items = List();
for (var district in districts) {
items.add(
DropdownMenuItem(
value: district,
child: Text(district.name),
),
);
}
return items;
}
onChangeDropdownItem(Province newProvince) {
// Add this
final String url =
'https://onobang.com/flutter/index.php?province=${newProvince.name}&district=${_selectedDistrict.name}';
setState(() {
_selectedProvince = newProvince;
finalUrl = url; // Add this
});
}
onChangeDistrict(District newDistrict) {
// Add this
final String url =
'https://onobang.com/flutter/index.php?province=${_selectedProvince.name}&district=${newDistrict.name}';
setState(() {
_selectedDistrict = newDistrict;
finalUrl = url; // Add this
});
}
#override
Widget build(BuildContext context) {
return new MaterialApp(
debugShowCheckedModeBanner: false,
home: new Scaffold(
appBar: new AppBar(
title: new Text("DropDown Button Example"),
),
body: new Container(
margin: const EdgeInsets.all(0.0),
padding: const EdgeInsets.all(13.0),
child: new Column(
children: <Widget>[
new Container(
margin: const EdgeInsets.all(0.0),
padding: const EdgeInsets.all(13.0),
decoration: new BoxDecoration(
border: new Border.all(color: Colors.blueGrey)),
child: new Text(
"Welcome to teacher list app, please select teacher by province / district and name"),
),
new Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text("Prov : "),
SizedBox(
height: 20.0,
),
DropdownButton(
value: _selectedProvince,
items: _dropdownMenuItems,
onChanged: onChangeDropdownItem,
),
SizedBox(
height: 20.0,
),
// Text('Selected: ${_selectedProvince.name}'),
// SizedBox(
// height: 20.0,
// ),
Text(" Dist : "),
SizedBox(
height: 20.0,
),
DropdownButton(
value: _selectedDistrict,
items: _dropdownMenuDistricts,
onChanged: onChangeDistrict,
),
SizedBox(
height: 20.0,
),
// Text('Selected: ${_selectedDistrict.name}'),
// SizedBox(
// height: 20.0,
// ),
// Padding(
// padding: const EdgeInsets.all(8.0),
// child: Text('$finalUrl'),
// ),
],
),
new Card(
child: new Center(
child: TextFormField(
decoration: InputDecoration(labelText: 'Teacher Name'),
))),
new FlatButton(
color: Colors.blue,
textColor: Colors.white,
disabledColor: Colors.grey,
disabledTextColor: Colors.black,
padding: EdgeInsets.all(8.0),
splashColor: Colors.blueAccent,
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecondWidget(value:"$finalUrl"))
);
// what action to show next screen
},
child: Text(
"Show List",
),
),
],
),
),
),
);
}
}
// ignore: must_be_immutable
class SecondWidget extends StatelessWidget
{
String value;
SecondWidget({Key key, #required this.value}):super(key:key);
#override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(title: Text("Page 2"),),
body: Column(children: <Widget>[
Text("I wish Show JSON Mysql listview with this URL : "+this.value),
RaisedButton(child: Text("Go Back"),
onPressed: () {
Navigator.pop(context);
}),
],)
);
}
}
any help very thanks before iam a beginner in flutter, and very dificult to learn flutter
Edit
If you mean click Menu Item and change _buildSearchResults's content,
your _buildSearchResults is based on List _searchResult, modify content as you do in onSearchTextChanged will work. In RaisedButton, you can do this with onPressed
RaisedButton(
padding: const EdgeInsets.all(8.0),
textColor: Colors.white,
color: Colors.blue,
onPressed: (newDistrict) {
setState(() {
_myDistrict = newDistrict;
_searchResult.clear();
//recreate your _searchResult again.
});
},
child: new Text("Submit"),
)
onChanged: (newDistrict) {
setState(() {
_myDistrict = newDistrict;
_searchResult.clear();
//recreate your _searchResult again.
});
},
If I understand you clear, you are trying to create DropdownMenuItem via JSON string get from API.
JSON from different API, you can join them
List<Map> _jsonApi1 = [
{"id": 0, "name": "default 1"}
];
List<Map> _jsonApi2 = [
{"id": 1, "name": "second 2"},
{"id": 2, "name": "third 3"}
];
List<Map> _myJson = new List.from(_jsonApi1)..addAll(_jsonApi2);
Generate menuitem
new DropdownButton<String>(
isDense: true,
hint: new Text("${_jsonApi1[0]["name"]}"),
value: _mySelection,
onChanged: (String newValue) {
setState(() {
_mySelection = newValue;
});
print(_mySelection);
},
items: _myJson.map((Map map) {
return new DropdownMenuItem<String>(
value: map["id"].toString(),
child: new Text(
map["name"],
),
);
}).toList(),
full code
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
// This is the theme of your application.
//
// Try running your application with "flutter run". You'll see the
// application has a blue toolbar. Then, without quitting the app, try
// changing the primarySwatch below to Colors.green and then invoke
// "hot reload" (press "r" in the console where you ran "flutter run",
// or simply save your changes to "hot reload" in a Flutter IDE).
// Notice that the counter didn't reset back to zero; the application
// is not restarted.
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
// This widget is the home page of your application. It is stateful, meaning
// that it has a State object (defined below) that contains fields that affect
// how it looks.
// This class is the configuration for the state. It holds the values (in this
// case the title) provided by the parent (in this case the App widget) and
// used by the build method of the State. Fields in a Widget subclass are
// always marked "final".
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
List<Map> _jsonApi1 = [
{"id": 0, "name": "default 1"}
];
List<Map> _jsonApi2 = [
{"id": 1, "name": "second 2"},
{"id": 2, "name": "third 3"}
];
List<Map> _myJson = new List.from(_jsonApi1)..addAll(_jsonApi2);
class _MyHomePageState extends State<MyHomePage> {
String _mySelection;
#override
Widget build(BuildContext context) {
return new Scaffold(
body: SafeArea(
child: Column(
children: <Widget>[
Container(
height: 500.0,
child: new Center(
child: new DropdownButton<String>(
isDense: true,
hint: new Text("${_jsonApi1[0]["name"]}"),
value: _mySelection,
onChanged: (String newValue) {
setState(() {
_mySelection = newValue;
});
print(_mySelection);
},
items: _myJson.map((Map map) {
return new DropdownMenuItem<String>(
value: map["id"].toString(),
child: new Text(
map["name"],
),
);
}).toList(),
),
),
),
],
),
),
);
}
}

How to add a widget by position on runtime in flutter?

I am trying to add a button on an image on tap position.
I have managed to get position on tap by using onTapUp's detail parameter.
However, I can't add an icon button when user taps on the image.
Below code shows my sample.
class ArticlesShowcase extends StatelessWidget {
final commentWidgets = List<Widget>();
#override
Widget build(BuildContext context) {
return new GestureDetector(
child: new Center(
child: Image.network(
'https://via.placeholder.com/300x500',
),
),
onTapUp: (detail) {
final snackBar = SnackBar(
content: Text(detail.globalPosition.dx.toString() +
" " +
detail.globalPosition.dy.toString()));
Scaffold.of(context).showSnackBar(snackBar);
new Offset(detail.globalPosition.dx, detail.globalPosition.dy);
var btn = new RaisedButton(
onPressed: () => {},
color: Colors.purple,
child: new Text(
"Book",
style: new TextStyle(color: Colors.white),
),
);
commentWidgets.add(btn);
},
);
}
}
I tried to add the button on the list but no chance.
So , there are a couple of things you are missing.
First you can't update a StatelessWidget state , so you need to use a StatefulWidget.
Second, when using a StatefulWidget , you need to call setState to update the State.
You will also need to use a Stack and Positioned widgets to put the buttons on your specific location.
Your code should end and look like this.
class ArticlesShowcaseState extends State<ArticlesShowcase> {
final commentWidgets = List<Widget>();
void addButton(detail) {
{
final snackBar = SnackBar(
content: Text(
"${detail.globalPosition.dx.toString()} ${detail.globalPosition.dy.toString()}"));
Scaffold.of(context).showSnackBar(snackBar);
var btn = new Positioned(
left: detail.globalPosition.dx,
top: detail.globalPosition.dy,
child: RaisedButton(
onPressed: () => {},
color: Colors.purple,
child: new Text(
"Book",
style: new TextStyle(color: Colors.white),
),
));
setState(() {
commentWidgets.add(btn);
});
}
}
#override
Widget build(BuildContext context) {
return Stack(
children: <Widget>[
GestureDetector(
child: new Center(
child: Image.network(
'https://via.placeholder.com/300x500',
),
),
onTapUp: (detail) => addButton(detail),
)
] +
commentWidgets,
);
}
}

Flutter: How can I select an image icon in a list without all icons in the list being selected?

I have created a List in Flutter using Sliver (Sliver Structure below):
return Scaffold(
body: CustomScrollView(
slivers: <Widget>[
SliverAppBar(
//leading: Icon(Icons.arrow_back),
expandedHeight: 150.0,
pinned: true,
),
SliverList(
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
final item = taskList[index];
return Card()
The Card has a Dismissible Widget encapsulated within which creates a ListTile. The Dismissible works fine and I can swipe to dismiss individual cells in the list.
The issue I am having is related to an IconButton in my ListTile. My aim is that whenever I tap the IconButton it should toggle an Icon Flag on or off for the individual cell, but what happens is that all of the Icon Buttons in the List are toggled. From investigating the Dismissible Widget code I can understand that I need to uniquely identify each cell for this to work, I've tried using a Key to make the cells unique but that hasn't worked. Is anybody able to steer me in the right direction? The code for the IconButton is below, I also attempted to add a key to the ListTile but that didn't work so I removed it.
IconButton(
key: Key(item),
icon: Icon(Icons.flag),
color: (isPriority) ? Colors.red : Colors.grey,
onPressed: _toggleFlag,
)
My toggleFlag code is below, I already have a setState in there, it toggles the flag but the issue is that it toggles all flags in the list when i want to toggle the flag of the cell that it belongs to:
void _toggleFlag() {
setState(() {
if (isPriority) {
isPriority = false;
} else {
isPriority = true;
}
});
}
Create your card like this
return new Users(example: taskList[index]);
then craete widget for card
class Users extends StatefulWidget
{
final String example;
const Users ({Key key, this.example}) : super(key: key);
#override
UserWidgets createState() => UserWidgets();
}
class UserWidgets extends State<Users>
{
#override
Widget build(BuildContext context)
{
return new Container(
child: Card(
child:new IconButton(
icon: Icon(Icons.flag),
color: (isPriority) ? Colors.red : Colors.grey,
onPressed: ()
{
setState(() {
if (isPriority) {
isPriority = false;
} else {
isPriority = true;
}
});
}
,
),
);
}
I have been able to simplify my code to capture all of it and show where the icon button fits in (the icon button is right at the bottom). I'm still getting the issue that if I tap on an icon flag all of the icon flags are then toggled on rather than the specific one that I tapped.
class HomePage extends StatefulWidget {
_HomePageDemoState createState() => _HomePageDemoState();
}
class _HomePageDemoState extends State<HomePage> {
List<String> taskList = [
'The Enchanted Nightingale',
'The Wizard of Oz',
'The BFG'
];
bool isPriority = false;
void _toggleFlag() {
setState(() {
if (isPriority) {
isPriority = false;
} else {
isPriority = true;
}
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: CustomScrollView(
slivers: <Widget>[
SliverList(
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
final item = taskList[index];
return Card(
elevation: 8.0,
child: ListTile(
contentPadding: EdgeInsets.all(0.0),
leading: Container(
color: (isPriority) ? Colors.red : Colors.grey,
//padding: EdgeInsets.only(right: 12.0),
padding: EdgeInsets.all(20.0),
child: Text(
'01',
style: TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.bold,
color: Colors.white),
),
),
title: Text('$item'), //Text('The Enchanted Nightingale'),
subtitle:
Text('Music by Julie Gable. Lyrics by Sidney Stein.'),
trailing: IconButton(
key: Key(item),
icon: Icon(Icons.flag),
color: (isPriority) ? Colors.red : Colors.grey,
onPressed: _toggleFlag,
),
),
);
},
childCount: taskList.length,
),
),
],
),
);
}
}