I am using an autocomplete textfield in my flutter application. While typing text in the textfield the user gets the suggestions (via JSON). Then the user should click on a suggestion and should be forwarded to the "SecondPage". At the same time the country of the selected player should also be passed to the "SecondPage".
In the part itemSubmitted I tried to integrate my plan but it doesn't work. The "SecondPage" doesn't start. Can you help here?
This is my code:
#override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomPadding: false,
appBar: AppBar(
title: Text('Search'),
),
body: new Center(
child: new Column(children: <Widget>[
new Column(children: <Widget>[
searchTextField = AutoCompleteTextField<PlayersForSearch>(
style: new TextStyle(color: Colors.black, fontSize: 16.0),
decoration: new InputDecoration(
suffixIcon: Container(
width: 85.0,
height: 60.0,
),
contentPadding: EdgeInsets.fromLTRB(10.0, 30.0, 10.0, 20.0),
filled: true,
hintText: 'Search Player Name',
hintStyle: TextStyle(color: Colors.black)),
itemSubmitted: (item) {
SecondPage(item.country);
MaterialPageRoute(builder: (context) => SecondPage(item.country));
setState(() => searchTextField.textField.controller.text =
item.autocompleteterm);
},
clearOnSubmit: false,
key: key,
suggestions: PlayerViewModel.player_search,
itemBuilder: (context, item) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(item.autocompleteterm,
style: TextStyle(
fontSize: 16.0
),),
Padding(
padding: EdgeInsets.all(15.0),
),
Text(item.country,
)
],
);
},
itemSorter: (a, b) {
return a.autocompleteterm.compareTo(b.autocompleteterm);
},
itemFilter: (item, query) {
return item.autocompleteterm
.toLowerCase()
.startsWith(query.toLowerCase());
}),
]),
])));
}
I believe what's missing is the Navigator.push call to push the SecondPage onto the stack of routes. A MaterialPageRoute will not place itself onto the stack of pages/routes.
Example
When you focus on the text field and press Enter, it will navigate to the SecondPage with the value of the TextFormField.
import 'package:flutter/material.dart';
class NavTextFieldPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Nav TextField Submit'),
),
body: NavTextfieldExample(),
);
}
}
class NavTextfieldExample extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
TextFormField(
decoration: InputDecoration(
labelText: 'Navigate to next page',
),
initialValue: 'Japan',
onFieldSubmitted: (item) {
/// Using default Navigator from Scaffold, *push* onto stack SecondPage
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => SecondPage(item)));
},
)
],
);
}
}
class SecondPage extends StatelessWidget {
final String country;
SecondPage(this.country);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Nav Second Page'),
),
body: Center(
child: Text('Country: $country'),
),
);
}
}
The key piece above is:
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => SecondPage(item)));
which uses the Navigator object to push routes onto your stack of routes (i.e. pages).
please try the following :
. create a SecondPage.dart
. put in a stateless or stateful Widget
. create a route in your materialApp()
Related
Hi I'm a beginner flutter developer, I have a StatefulWidget widget and a ListView here is a button to display ModalBottomSheet
The ModalBottomSheet has a FilterChip widget that allows the user to apply some filters to the ListView, but I would like to keep the FilterChip state even after the user pop the ModalBottomSheet.
class AvailableMeals extends StatefulWidget {
static const routeName = 'available-meals';
#override
_AvailableMealsState createState() => _DietAvailableMealsState();
}
class _DietAvailableMealsState extends State<DietAvailableMeals> {
bool status = false;
#override
Widget build(BuildContext context) {
buildFilterBox() {
return Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
child: Text(
'SelectFilter',
style: TextStyle(fontSize: 10.sp),
),
),
Container(
child: Wrap(
spacing: 25,
children: [
FilterChip(
selected: status,
label: Text('Vegan'),
onSelected: (value) {
setState(() {
status = value;
});
})
],
),
),
],
),
);
}
return Scaffold(
appBar: AppBar(
title: Text('Meals'),
actions: [
IconButton(
onPressed: () {
showModalBottomSheet(
context: context,
builder: (context) {
return buildFilterBox();
});
},
icon: Icon(Icons.search))
],
),
body: Container(child : Column(children: [
Expanded(
child: ListView.builder(
itemBuilder: (ctx, index) => ChangeNotifierProvider.value(
value: _customList[index], child: MealCard(_customList[index])),
itemCount: _customList.length,
));
] ))
}
I'm new to flutter.
I need to get product information through a form using flutter provider.
I can get one object(like String name value only). But when I add multiple parameters, it shows the following error.
Too many positional arguments: 1 expected, but 3 found.
This is the code I wrote.
Model class
class Item {
String itemName;
String description;
double itemPrice;
Item(this.itemName, this.description, this.itemPrice);
}
ChangeNotifier class
class ItemAddNotifier extends ChangeNotifier {
List<Item> itemList = [];
addItem(String itemName, String description, double itemPrice) {
Item item = Item(itemName, description, itemPrice);
itemList.add(item);
notifyListeners();
}
}
Add items
class AddItems extends StatelessWidget {
final TextEditingController _itemNameTextEditing = TextEditingController();
final TextEditingController _itemDescriptionTextEditing =
TextEditingController();
final TextEditingController _itemPriceTextEditing = TextEditingController();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Kavishka'),
),
body: Container(
padding: EdgeInsets.all(30.0),
child: Column(
children: [
TextField(
controller: _itemNameTextEditing,
decoration: InputDecoration(
contentPadding: EdgeInsets.all(15.0),
hintText: 'Item Name',
),
),
SizedBox(
height: 20.0,
),
TextField(
controller: _itemDescriptionTextEditing,
decoration: InputDecoration(
contentPadding: EdgeInsets.all(15.0),
hintText: 'Item Description',
),
),
SizedBox(
height: 20.0,
),
TextField(
controller: _itemPriceTextEditing,
decoration: InputDecoration(
contentPadding: EdgeInsets.all(15.0),
hintText: 'Item Price',
),
),
SizedBox(
height: 20.0,
),
RaisedButton(
child: Text('ADD ITEM'),
onPressed: () async {
if (_itemNameTextEditing.text.isEmpty) {
return;
}
await Provider.of<ItemAddNotifier>(context, listen: false)
.addItem(
_itemNameTextEditing.text,
_itemDescriptionTextEditing.text,
_itemPriceTextEditing.text);
Navigator.pop(context);
},
),
],
),
),
);
}
}
Home Screen
class HomeScreen extends StatelessWidget {
const HomeScreen({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Kavishka'),
actions: [
IconButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
fullscreenDialog: true,
builder: (context) {
return AddItems();
},
),
);
},
icon: Icon(Icons.add))
],
),
body: Container(
padding: EdgeInsets.all(30.0),
child: Column(
children: [
Consumer<ItemAddNotifier>(builder: (context, itemAddNotifier, _) {
return ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: itemAddNotifier.itemList.length,
itemBuilder: (context, index) {
return Padding(
padding: EdgeInsets.all(15.0),
child: Column(
children: [
Text(
itemAddNotifier.itemList[index].itemName,
style:
TextStyle(fontSize: 20.0, color: Colors.black),
),
],
),
);
});
})
],
),
),
);
}
}
Main
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (BuildContext context) {
return ItemAddNotifier();
},
child: MaterialApp(
home: Container(
color: Colors.white,
child: HomeScreen(),
),
),
);
}
}
It shows the error in Item item = Item(itemName, description, itemPrice); line.
If someone can help me to fix this issue.
Thank you.
When I press my card, I want to set my card data into the text field.
my Card Widget and it's another stateful widget. And I need to set this card data into my text field
Widget build(BuildContext context) {
return Scaffold(
body: ListView(
shrinkWrap: true,
children: <Widget>[
Form(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: TextFormField(
decoration: InputDecoration(
labelText: "CupCake Name",
controller: cupCake,
onChanged: (cupcake) {
cupcakeName = cupcake;
},
),
),
),
]
LoadData(),
),
);
}
This is my Card Widget and it's another stateful widget. And I need to set this card data into my text field
class LoadData extends StatefulWidget {
const LoadData({Key? key}) : super(key: key);
#override
_LoadDataState createState() => _LoadDataState();
}
class _LoadDataState extends State<LoadData> {
#override
Widget build(BuildContext context) {
return Container(
child: ListView(
return GestureDetector(
onTap: () => {print("Test")},
child: Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12)),
child: Container(
padding: EdgeInsets.all(16),
child: Column(
children: <Widget>[
Text(
data['cupcake_name'],
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 4),
Text(
data['description'],
style: TextStyle(
fontSize: 20,
),
),
],
);
}).toList(),
),
}
}
Take a look at flutter simple state management. Basically as you have state that is shared and pertinent to a sub-tree of your widget tree you should encapsulate and lift that state as high as the first widget that needs to interact with it.
1 create the model which will handle the needed state
class CupCakeState extends ChangeNotifier {
CupCake? cupcake;
void selectCupcake(CupCake newCake){
this.cupCake=newCupcake;
notifyListeners();
}
2 Provide the model in the widget tree
ChangeNotifierProvider(
create: (context) => CupCakeState(),
child: const MyApp(),
),
3 Now you can use it either reading the context.
In your card:
class _LoadDataState extends State<LoadData> {
#override
Widget build(BuildContext context) {
return Container(
child: ListView(
return GestureDetector(
onTap: () => {context.read<CupCakeState>().selectCupcake(CupCake(name:data['cupcake_name'],price:data['cupcake_price']))},
...
Or creating a widget that rebuilds everytime you call notifylisteners()
Consumer<CupCakeState>(
builder: (context, cupcpakeState, child) {
cupcake.value=cupcpakeState.price;//assign the price to the controller
return TextFormField(
decoration: InputDecoration(
labelText: "CupCake Name",
controller: cupCake,
onChanged: (cupcake) {
cupcakeName = cupcake;
},
),
},
)
I'm using the Flutter BLoC package for manage the state of my app, but since last package update (v0.22.1) I have a strange behavior.
In simple I have a StreamSubscription listener on PositionBloc's state in EventsBloc but when I add an event from PositionBloc the listener not work.
The strangest thing is that the first time I add the event from EventsBloc the listener work, but after seems to be completely ignored.
This is my build tree:
main.dart: Here I show home page or the login page based on authentication. AuthenticationBloc and MoviesBloc aren't important or LocalsBloc the focus is on PositionBloc.
class App extends StatelessWidget {
...
#override
Widget build(BuildContext context) {
return BlocProvider(
builder: (context) => MoviesBloc()..add(LoadMovies()),
child: MaterialApp(
home: BlocBuilder<AuthenticationBloc, AuthenticationState>(
builder: (context, state) {
if (state is Unauthenticated) {
return Login(
authenticationRepository: _authenticationRepository,
);
}
if (state is Authenticated) {
return MultiBlocProvider(
providers: [
BlocProvider<LocalsBloc>(
builder: (context) => LocalsBloc()..add(LoadLocals()),
),
BlocProvider<PositionBloc>(
builder: (context) => PositionBloc(
localsBloc: BlocProvider.of<LocalsBloc>(context),
),
)
],
child: Home(),
);
}
return Splash();
},
),
),
);
}
}
home.dart: This is a StatefulWidget for manage TabBarView and here I provide EventsBloc to the widget EventsCarousel. In SearchBar widget I have the trigger for dispatch event and so rebuild the EventsCarousel based on selected position.
class _HomeState extends State<Home> with SingleTickerProviderStateMixin {
...
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: TabBarView(
children: <Widget>[
Stack(
alignment: Alignment.topCenter,
children: <Widget>[
BlocProvider<EventsBloc>(
builder: (context) => EventsBloc(),
child: EventsCarousel(),
),
Positioned(
child: SearchBar(),
),
],
),
MoviesList(),
Settings(),
],
controller: _tabController,
),
),
bottomNavigationBar: Material(
child: TabBar(
indicatorColor: Colors.deepOrange,
tabs: <Tab>[
Tab(
icon: Icon(
FontAwesomeIcons.home
),
),
Tab(
icon: Icon(
FontAwesomeIcons.bullhorn,
),
),
Tab(
icon: Icon(
FontAwesomeIcons.cogs,
),
),
],
controller: _tabController,
),
),
);
}
search_bar.dart: This is a StatefulWidget for manage _textController and _focusNode. Here I have my app state changer. I use Flutter TypeAhead package for build the search bar and the entries of my search bar is provided from LocalsBloc that we see in main.dart. When I tap on an entry I add the event UpdatePosition(local) to PositionBloc.
class _SearchBarState extends State<SearchBar> {
...
#override
Widget build(BuildContext context) {
return BlocBuilder<PositionBloc, PositionState>(
builder: (context, state) {
if (state is PositionUpdated) {
if (!_focusNode.hasFocus) {
_textController.text = state.position.local.description;
}
return Container(
decoration: BoxDecoration(
color: Colors.white,
),
width: MediaQuery.of(context).size.width * 0.75,
child: TypeAheadField<Local>(
getImmediateSuggestions: true,
textFieldConfiguration: TextFieldConfiguration(
decoration: InputDecoration(
border: OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(10.0),
),
),
hintText: "Inserisci una posizione",
contentPadding: EdgeInsets.all(15),
),
focusNode: _focusNode,
controller: _textController,
),
suggestionsCallback: (String pattern) {
return (BlocProvider.of<LocalsBloc>(context).state as LocalsLoaded)
.locals
.where(
(local) =>
local.description
.toLowerCase()
.contains(pattern.toLowerCase()),
)
.toList();
},
noItemsFoundBuilder: (context) {
return Text('Nessun risultato trovato');
},
itemBuilder: (context, Local suggestion) {
return Card(
child: ListTile(
title: Text(suggestion.description),
subtitle: Text(suggestion.town),
trailing: Icon(Icons.gps_not_fixed),
),
);
},
onSuggestionSelected: (Local suggestionSelected) {
BlocProvider.of<PositionBloc>(context).add(
UpdatePosition(suggestionSelected),
);
}),
);
} else {
return Container();
}
},
);
}
I have standards Bloc boilerplate for events and states and in particular for EventsBloc as I said I have this subscription:
EventsBloc({#required PositionBloc positionBloc})
: assert(PositionBloc != null),
_positionBloc = positionBloc {
positionSubscription = positionBloc.listen((state) {
if (state is PositionUpdated) {
add(LoadEvents(state.local));
}
});
This listener not work after the first widgets tree build, but when I add event UpdatePosition from selection of an entry in the search bar the state of PositionBloc change and the event is correctly mapped to PositionUpdated. This is a very strange situation, can help me?
I just noticed that I had missed a super-call in the CTORs initializer for my PositionUpdated state so the listener was not invoked. This is my mistake and I had been following it for three days in debug.
I'm new to flutter, I trying to pass a value from textfield and when i click a button submit, display it in textformfield in another screen, my problem, I don't know the right way to get value
Some Code :
String txt = "";
TextEditingController controllerTxt = new TextEditingController();
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: Text('Create'),
actions: <Widget>[
FlatButton(
child: Text('Submit'),
textColor: Colors.white,
onPressed: () {
setState(() {
//txt = (controllerTxt.text);
Navigator.pushNamed(context, '/ResultPage');
});
},
),
],
),
body: new Container(
child: new Column(
children: <Widget>[
new TextField(
controller: controllerTxt,
maxLines: 5,
decoration: new InputDecoration(
),
),
],
),
),
);
}
}
class _ResultPageState extends State<ResultPage> {
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: Text('Result'),
),
body: new Container(
padding: EdgeInsets.all(10.0),
child: new Column(
children: <Widget>[
new TextFormField(
decoration: InputDecoration(
labelText: 'Name :',
),
),
new Text("${controllerTxt.text}"),
],
),
),
);
}
}
I have done the same thing by passing data through the constructor
Navigator.push(context,
MaterialPageRoute(builder: (context) => ResultPage(controllerTxt.text)));
class ResultPage extends StatefulWidget {
final String result;
ResultPage(this.result);