model class:
Venue with ChangeNotifier{
String id;
update(String venueId) {
id = venueId;
notifyListeners();
}
}
Trying to get the id value like so:
Widget _buildContents(BuildContext context) {
final venue = Provider.of<Venue>(context);
final id = venue.id;
print('##########'); //// trying to get the the id here.
}
My id is supposed to be updated in the onTap callback of a dropDownButton:
DropdownButton(
....
items: venues.map((venue) {
return DropdownMenuItem<String>(
onTap: () {
venue.update(venue.id);
},
value: venue.name,
child: Text(
venue.name,
style: TextStyle(fontSize: 28),
),
);
}).toList(),
.....
)
And the Provider.. is above the widgets:
MultiProvider(providers: [
ChangeNotifierProvider<Venue>(create: (_) => Venue()),
], child: HomePage());
Something is wrong..help!?
You can copy paste run full code below
You can use DropdownButton<Venue> and call venue.update in onChanged
code snippet
DropdownButton<Venue>(
value: dropdownValue,
icon: Icon(Icons.arrow_downward),
iconSize: 24,
elevation: 16,
style: TextStyle(color: Colors.deepPurple),
underline: Container(
height: 2,
color: Colors.deepPurpleAccent,
),
onChanged: (Venue newValue) {
setState(() {
dropdownValue = newValue;
venue.update(newValue.id);
});
},
items: venues.map((venue) {
return DropdownMenuItem<Venue>(
value: venue,
child: Text(
venue.name,
style: TextStyle(fontSize: 28),
),
);
}).toList()
working demo output
I/flutter (27988): ########## 1
I/flutter (27988): ########## 2
working demo
full code
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class Venue with ChangeNotifier {
String id;
String name;
update(String venueId) {
id = venueId;
notifyListeners();
}
Venue({this.id, this.name});
}
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MultiProvider(providers: [
ChangeNotifierProvider<Venue>(create: (_) => Venue()),
], child: HomePage()),
);
}
}
class HomePage extends StatefulWidget {
HomePage({Key key}) : super(key: key);
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
Venue dropdownValue;
List<Venue> venues = [
Venue(id: "1", name: "name1"),
Venue(id: "2", name: "name2"),
Venue(id: "3", name: "name3"),
];
#override
Widget build(BuildContext context) {
final venue = Provider.of<Venue>(context);
final id = venue.id;
print('########## $id');
return Scaffold(
appBar: AppBar(
title: Text("demo"),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
DropdownButton<Venue>(
value: dropdownValue,
icon: Icon(Icons.arrow_downward),
iconSize: 24,
elevation: 16,
style: TextStyle(color: Colors.deepPurple),
underline: Container(
height: 2,
color: Colors.deepPurpleAccent,
),
onChanged: (Venue newValue) {
setState(() {
dropdownValue = newValue;
venue.update(newValue.id);
});
},
items: venues.map((venue) {
return DropdownMenuItem<Venue>(
value: venue,
child: Text(
venue.name,
style: TextStyle(fontSize: 28),
),
);
}).toList(),
),
],
),
),
);
}
}
Related
class DropDown extends StatefulWidget {
const DropDown({
this.data,
this.hint,
Key key,
}) : super(key: key);
final List<String> data;
final String hint;
#override
_DropDownState createState() => _DropDownState();
}
String _chosenValue1;
class _DropDownState extends State<DropDown> {
#override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: Container(
width: 250,
padding: const EdgeInsets.all(0.0),
child: DropdownButton<String>(
iconSize: 30,
isExpanded: true,
value: _chosenValue1,
//elevation: 5,
items: widget.data.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
hint: Text(
widget.hint,
style: TextStyle(
color: Colors.black,
fontSize: 13,
fontWeight: FontWeight.w600,
),
),
onChanged: (String value) {
setState(() {
_chosenValue1 = value;
});
},
),
),
);
}
}
DropDown(
data: [
'Non-Blanchable',
'Partial thickness skin',
'Full thickness skin loss involving damage or necrosis',
'Obscured by necrosis'
],
hint: 'Assessment',
),
DropDown(
data: [
'Indistinct, diffuse,none ',
'Distinct,outline clearly'
],
hint: 'Assessment',
),
i have been stuck on this problem for a while now, When i have the same data inside the data it works however all the dropdown would become the same, I want to be able to have different data for different dropdown , but when i do so the error is caused and i cant figure out whats wrong with it
import 'package:flutter/material.dart';
class DropDown extends StatefulWidget {
DropDown({
this.data,
this.hint,
this.initialValue,
Key? key,
}) : super(key: key);
final List<String>? data;
final String? hint;
final String? initialValue;
String chosenValue1 = "";
#override
_DropDownState createState() => _DropDownState();
}
class _DropDownState extends State<DropDown> {
#override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: Container(
width: 250,
padding: const EdgeInsets.all(0.0),
child: DropdownButton<String>(
iconSize: 30,
isExpanded: true,
value: widget.initialValue!.isEmpty ? null : widget.initialValue!,
//elevation: 5,
items: widget.data!.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
hint: Text(
widget.hint!,
style: const TextStyle(
color: Colors.black,
fontSize: 13,
fontWeight: FontWeight.w600,
),
),
onChanged: (value) {
setState(() {
widget.chosenValue1 = value!;
});
},
),
),
);
}
}
import 'package:flutter/material.dart';
import 'dropdown.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
// This call to setState tells the Flutter framework that something has
// changed in this State, which causes it to rerun the build method below
// so that the display can reflect the updated values. If we changed
// _counter without calling setState(), then the build method would not be
// called again, and so nothing would appear to happen.
_counter++;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
DropDown(
data: const [
'Non-Blanchable',
'Partial thickness skin',
'Full thickness skin loss involving damage or necrosis',
'Obscured by necrosis'
],
hint: 'Assessment',
initialValue: "Non-Blanchable",
),
DropDown(
data: const [
'Indistinct, diffuse,none',
'Distinct,outline clearly'
],
hint: 'Assessment',
initialValue: "",
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
Use the above code it will fix ur error
I tried running your code and, after making your data and hint required params and moving the chosenValue variable inside your _DropDownState, it works perfectly fine. Can you maybe share some steps with how to reproduce the error that you're seeing, because I see two different dropdowns with values I can select independently of each other.
As per your description of how to reproduce the error, I've tried adding navigation between two screens, but it still all works as intended.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Dropdowns(),
);
}
}
class Dropdowns extends StatelessWidget {
const Dropdowns();
#override
Widget build(BuildContext context) {
return Scaffold(
body: Padding(
padding: EdgeInsets.all(40),
child: Column(
children: [
Text('This is the first screen'),
DropDown(
data: [
'Non-Blanchable',
'Partial thickness skin',
'Full thickness skin loss involving damage or necrosis',
'Obscured by necrosis'
],
hint: 'Assessment',
),
DropDown(
data: ['Indistinct, diffuse,none ', 'Distinct,outline clearly'],
hint: 'Assessment',
),
ElevatedButton(
child: Text('Go to second screen'),
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => SecondScreen(),
),
);
},
),
],
),
),
);
}
}
class DropDown extends StatefulWidget {
const DropDown({
required this.data,
required this.hint,
Key? key,
}) : super(key: key);
final List<String> data;
final String hint;
#override
_DropDownState createState() => _DropDownState();
}
class _DropDownState extends State<DropDown> {
String? _chosenValue1;
#override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: Container(
width: 250,
padding: const EdgeInsets.all(0.0),
child: DropdownButton<String>(
iconSize: 30,
isExpanded: true,
value: _chosenValue1,
//elevation: 5,
items: widget.data.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
hint: Text(
widget.hint,
style: TextStyle(
color: Colors.black,
fontSize: 13,
fontWeight: FontWeight.w600,
),
),
onChanged: (String? value) {
setState(() {
_chosenValue1 = value;
});
},
),
),
);
}
}
class SecondScreen extends StatelessWidget {
const SecondScreen({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('SECOND SCREEN'),
),
body: Padding(
padding: EdgeInsets.all(40),
child: Column(
children: [
Text('This is the second screen'),
DropDown(
data: [
'Non-Blanchable',
'Partial thickness skin',
'Full thickness skin loss involving damage or necrosis',
'Obscured by necrosis'
],
hint: 'Assessment',
),
DropDown(
data: ['Indistinct, diffuse,none ', 'Distinct,outline clearly'],
hint: 'Assessment',
),
],
),
),
);
}
}
onChanged: (String value) {
setState(() {
_chosenValue = value;
selcat = null; use dropdown as category
_chosenValue == null
? Container()
: _chosenValue == "hi"
? _hi()
: _chosenValue == "hello"
? _hello()
: Container(),
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
static const String _title = 'Flutter Code Sample';
#override
Widget build(BuildContext context) {
return MaterialApp(
title: _title,
home: Scaffold(
appBar: AppBar(title: const Text(_title)),
body: Center(
child: MyStatefulWidget(),
),
),
);
}
}
class MyStatefulWidget extends StatefulWidget {
MyStatefulWidget({Key key}) : super(key: key);
#override
_MyStatefulWidgetState createState() => _MyStatefulWidgetState();
}
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
String dropdownValue = 'One';
#override
Widget build(BuildContext context) {
return DropdownButton<String>(
value: dropdownValue,
icon: Icon(Icons.arrow_downward),
iconSize: 15,
elevation: 16,
style: TextStyle(color: Colors.deepPurple),
underline: Container(
height: 2,
color: Colors.deepPurpleAccent,
),
onChanged: (String newValue) {
setState(() {
dropdownValue = newValue;
});
},
items: <String>['One', 'Two', 'Free', 'Four']
.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
);
}
}
You can add width: (specification) and height: (specification) in your dropdown list. Specification -> number.
Please, use the Code Sample formatting option.
you can do it like this :
return Container(
child: DropdownButton(
value: dropdownValue,
icon: Icon(Icons.arrow_downward),
iconSize: 15,
elevation: 16,
style: TextStyle(color: Colors.deepPurple),
underline: Container(
height: 2,
color: Colors.deepPurpleAccent,
),
onChanged: (newValue) {
setState(() {
dropdownValue = newValue;
});
},
items: ['One', 'Two', 'Free', 'Four'] .map<DropdownMenuItem>((String value) {
return DropdownMenuItem(
value: value,
child: Container(
height: 100,
width: 200,
alignment: Alignment.centerLeft,
child: Text(value)
)
);
}).toList(),
)
);
Btw, please use the Code Sample formatting option.
I have a very simple list of maps.
List<Map<String, String>> items = [
{ 'a': 'Some Text' },
{ 'b': 'Another Text' },
];
I want to map the above list to a dropdown list.
DropdownButton<String>(
hint: Text('Select a value'),
items: items.map((item) {
return DropdownMenuItem<String>(
value: // how to get key here a, b
child: // how to get value 'Some Text', 'Another Text'
);
}).toList(),
onChanged: (String newValue) {
setState(() {
// ...
});
},
),
)
How to get the key of the map, item has a property keys but not key and values and not value.
For this particular input:
List<Map<String, String>> items = [
{ 'a': 'Some Text' },
{ 'b': 'Another Text' },
];
You can do a workaround by accessing all the keys/values using getters and locating its very first element like this.
DropdownButton<String>(
items: items.map((item) {
return DropdownMenuItem<String>(
value: item.keys.first,
child: Text(item.values.first),
);
}).toList(),
onChanged: (value){},
)
You can copy paste run full code below
You need to use DropdownButton<Map<String, String>>
You can adjust Text("${value.keys.first} ${value.values.first}") per your request
code snippet
DropdownButton<Map<String, String>>(
value: dropdownValue,
icon: Icon(Icons.arrow_downward),
iconSize: 24,
elevation: 16,
style: TextStyle(color: Colors.deepPurple),
underline: Container(
height: 2,
color: Colors.deepPurpleAccent,
),
onChanged: (Map<String, String> newValue) {
setState(() {
dropdownValue = newValue;
print(
"${dropdownValue.keys.first} ${dropdownValue.values.first}");
});
},
items: items.map<DropdownMenuItem<Map<String, String>>>(
(Map<String, String> value) {
return DropdownMenuItem<Map<String, String>>(
value: value,
child: Text("${value.keys.first} ${value.values.first}"),
);
}).toList(),
),
working demo
full code
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
List<Map<String, String>> items = [
{'a': 'Some Text'},
{'b': 'Another Text'},
];
Map<String, String> dropdownValue;
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
DropdownButton<Map<String, String>>(
value: dropdownValue,
icon: Icon(Icons.arrow_downward),
iconSize: 24,
elevation: 16,
style: TextStyle(color: Colors.deepPurple),
underline: Container(
height: 2,
color: Colors.deepPurpleAccent,
),
onChanged: (Map<String, String> newValue) {
setState(() {
dropdownValue = newValue;
print(
"${dropdownValue.keys.first} ${dropdownValue.values.first}");
});
},
items: items.map<DropdownMenuItem<Map<String, String>>>(
(Map<String, String> value) {
return DropdownMenuItem<Map<String, String>>(
value: value,
child: Text("${value.keys.first} ${value.values.first}"),
);
}).toList(),
),
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
How can i make routes to different pages for each element of a gridView list model.
i found this example for a filtre lis view, and i wanted to add a route for each element of the list, i tried to implement wrap it in an InkWell but it resulted to navigate on only the first route.
Here the full code for the example
import 'package:flutter/material.dart';
class Model {
String id;
String name;
String title;
Model({this.id, this.name, this.title});
}
class SearchList extends StatefulWidget {
SearchList({Key key}) : super(key: key);
#override
_SearchListState createState() => _SearchListState();
}
class _SearchListState extends State<SearchList> {
Widget appBarTitle = Text(
"Search Demo",
style: TextStyle(color: Colors.white),
);
Icon actionIcon = Icon(
Icons.search,
color: Colors.orange,
);
final key = GlobalKey<ScaffoldState>();
final TextEditingController _searchQuery = TextEditingController();
List<Model> _list;
List<Model> _searchList = List();
bool _IsSearching;
String _searchText = "";
#override
void initState() {
super.initState();
_IsSearching = false;
init();
}
void init() {
_list = List();
_list.add(
Model(id: "1", name: "name 1", title: "a title 1"),
);
_list.add(
Model(id: "2", name: "name 2", title: "a title 2"),
);
_list.add(
Model(id: "3", name: "name 3", title: "b title 3"),
);
_list.add(
Model(id: "4", name: "name 4", title: "b title 4"),
);
_list.add(
Model(id: "5", name: "name 5", title: "b title 5"),
);
_searchList = _list;
_searchQuery.addListener(() {
if (_searchQuery.text.isEmpty) {
setState(() {
_IsSearching = false;
_searchText = "";
_buildSearchList();
});
} else {
setState(() {
_IsSearching = true;
_searchText = _searchQuery.text;
_buildSearchList();
});
}
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
key: key,
appBar: buildBar(context),
body: GridView.builder(
itemCount: _searchList.length,
itemBuilder: (context, index) {
return GridItem(_searchList[index]);
},
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
)));
}
List<Model> _buildSearchList() {
if (_searchText.isEmpty) {
return _searchList = _list;
} else {
_searchList = _list
.where((element) =>
element.name.toLowerCase().contains(_searchText.toLowerCase()) ||
element.title.toLowerCase().contains(_searchText.toLowerCase()))
.toList();
print('${_searchList.length}');
return _searchList;
}
}
Widget buildBar(BuildContext context) {
return AppBar(
centerTitle: true,
title: appBarTitle,
iconTheme: IconThemeData(color: Colors.orange),
backgroundColor: Colors.black,
actions: <Widget>[
IconButton(
icon: actionIcon,
onPressed: () {
setState(() {
if (this.actionIcon.icon == Icons.search) {
this.actionIcon = Icon(
Icons.close,
color: Colors.orange,
);
this.appBarTitle = TextField(
controller: _searchQuery,
style: TextStyle(
color: Colors.orange,
),
decoration: InputDecoration(
hintText: "Search here..",
hintStyle: TextStyle(color: Colors.white)),
);
_handleSearchStart();
} else {
_handleSearchEnd();
}
});
},
),
]);
}
void _handleSearchStart() {
setState(() {
_IsSearching = true;
});
}
void _handleSearchEnd() {
setState(() {
this.actionIcon = Icon(
Icons.search,
color: Colors.orange,
);
this.appBarTitle = Text(
"Search Demo",
style: TextStyle(color: Colors.white),
);
_IsSearching = false;
_searchQuery.clear();
});
}
}
class GridItem extends StatelessWidget {
final Model model;
GridItem(this.model);
Widget build(BuildContext context) {
return Card(
margin: EdgeInsets.fromLTRB(5, 5, 5, 7),
elevation: 10.0,
child: InkWell(
splashColor: Colors.orange,
onTap: () {
print(model.id);
},
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
AspectRatio(
aspectRatio: 18.0 / 11.0,
child: Image.network(
'https://picsum.photos/250?image=9',
fit: BoxFit.scaleDown,
),
),
Padding(
padding: EdgeInsets.fromLTRB(10.0, 15.0, 0.0, 0.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
this.model.name,
style: TextStyle(
fontFamily: 'Raleway',
fontWeight: FontWeight.bold,
fontSize: 14.0),
maxLines: 1,
),
SizedBox(height: 0.0),
Text(
model.title,
style: TextStyle(fontFamily: 'Roboto'),
),
],
),
),
],
),
),
);
}
}
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: SearchList(),
);
}
}
working demo :
enter image description here
I think, from the beginning, you know which page should be open for each item of your grid. In my case had a solution like this:
onTap: (){
Navigator.push(context, item1.routeName);
},
I had something like this for each item:
Items item1 = Items(
title: "First Title",
routeName: MaterialPageRoute(builder: (context)=>DetailPage1()),
);
The route is simply saved in each item.
In your case, it should look like:
_list.add(
Model(id: "5", name: "name 5", title: "b title 5", routeName: MaterialPageRoute(builder: (context)=>DetailPage5()),
);
it did works thank's to #Celt K. B.
i followed his instruction, and add routeName to class Model
class Model {
String id;
String name;
String title;
final routeName;
Model({this.id, this.name, this.title, this.routeName});
}
Sorry for late answer. But you need create just one page called ModelDetail, passing an instance of Model as a parameter like this, by example:
class ModelDetail extends StatefulWidget {
final Model model;
ModelDetail({Key key, this.model}) : super(key: key);
#override
_ModelDetailState createState() => _ModelDetailState();
}
class _ModelDetailState extends State<ModelDetail> {
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text(widget.model.title)),
body: Center(child: Container(child: Text(widget.model.name),),),
);
}
And at the onTap you need just call the Navigator passing the model to the ModelDetail page, like this:
onTap: () {
print(model.id);
//Navigate to ModelDetail page, passing the model as a parameter
Navigator.push(context, MaterialPageRoute(builder: (context) => ModelDetail(model: model)),);
},
I'm trying to create different widgets in TypeAhead suggestion depends on suggestion.subName.length
1. ListTile with a subTitle
2. ListTile without subTitle
TypeAhead(
...
itemBuilder: (context, suggestion) {
return ListTile(
dense: true,
title: AutoSizeText(
suggestion.primeName,
maxLines: 1,
overflow: TextOverflow.ellipsis,
minFontSize: 20,
),
subtitle: suggestion.subName.length == 0 ? null:AutoSizeText(
suggestion.subName.join(', '),
maxLines: 1,
overflow: TextOverflow.ellipsis,
minFontSize: 15,
),
);
},
...
But everything comes back with a subtitle.
What could cause that? Is it possible to make 2 different types of widgets in TypeAhead?
You can copy paste run full code below
I use the following example to simulate this case
You can return Container() not null
subtitle: suggestion.subName.length == 0 ? Container() : AutoSizeText(
or put condition in itemBuilder, for more complex condition you can use if
itemBuilder: (context, suggestion) {
return suggestion.subName.length == 0 ? ListTile(...) : ListTile(...);
working demo
full code
import 'package:flutter/material.dart';
import 'dart:math';
import 'package:flutter_typeahead/flutter_typeahead.dart';
class BackendService {
static Future<List> getSuggestions(String query) async {
await Future.delayed(Duration(seconds: 1));
return List.generate(3, (index) {
return {'name': query + index.toString(), 'price': Random().nextInt(100)};
});
}
}
class CitiesService {
static final List<String> cities = [
'Beirut',
'Damascus',
'San Fransisco',
'Rome',
'Los Angeles',
'Madrid',
'Bali',
'Barcelona',
'Paris',
'Bucharest',
'New York City',
'Philadelphia',
'Sydney',
];
static List<String> getSuggestions(String query) {
List<String> matches = List();
matches.addAll(cities);
matches.retainWhere((s) => s.toLowerCase().contains(query.toLowerCase()));
return matches;
}
}
class NavigationExample extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.all(32.0),
child: Column(
children: <Widget>[
SizedBox(
height: 10.0,
),
TypeAheadField(
textFieldConfiguration: TextFieldConfiguration(
autofocus: true,
style: DefaultTextStyle.of(context)
.style
.copyWith(fontStyle: FontStyle.italic),
decoration: InputDecoration(
border: OutlineInputBorder(),
hintText: 'What are you looking for?'),
),
suggestionsCallback: (pattern) async {
return await BackendService.getSuggestions(pattern);
},
itemBuilder: (context, suggestion) {
return ListTile(
leading: Icon(Icons.shopping_cart),
title: Text(suggestion['name']),
subtitle: suggestion['price'] < 20
? Container()
: Text('\$${suggestion['price']}'),
);
},
onSuggestionSelected: (suggestion) {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => ProductPage(product: suggestion)));
},
),
],
),
);
}
}
class ProductPage extends StatelessWidget {
final Map<String, dynamic> product;
ProductPage({this.product});
#override
Widget build(BuildContext context) {
return Scaffold(
body: Padding(
padding: const EdgeInsets.all(50.0),
child: Column(
children: [
Text(
this.product['name'],
style: Theme.of(context).textTheme.headline,
),
Text(
this.product['price'].toString() + ' USD',
style: Theme.of(context).textTheme.subhead,
)
],
),
),
);
}
}
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
NavigationExample(),
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}