This question already has answers here:
Passing data between screens in Flutter
(13 answers)
Closed 2 years ago.
I am fairly new in Flutter. I have an issue where I am stock. I am trying to parse data from one widget to another StatefulWidget.
I have this widget where I try to parse data from
class MaltInput extends StatefulWidget {
#override
_MaltInputState createState() => _MaltInputState();
}
class _MaltInputState extends State<MaltInput> {
List<String> malt = ['Malt 1', 'Malt 2', 'Malt 3'];
String maltpick = "";
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Malt input'),
),
body: ListView.builder(
itemCount: malt.length,
itemBuilder: (context, index){
return Card(
child: ListTile(
onTap: (){
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Test(malt[index]),
));
},
title: Text(malt[index]),
),
);
},
),
);
}
}
Parse to this widget
class Test extends StatefulWidget {
String malt;
Test({this.malt});
#override
_TestState createState() => _TestState();
}
class _TestState extends State<Test> {
String malt;
_TestState({this.malt});
List<String> items = [];
final TextEditingController ectrl = TextEditingController();
#override
Widget build(BuildContext context) {
String maltpick;
maltpick = (widget.malt);
//widget.malt = "";
return Scaffold(
appBar: AppBar(
title: Text('Dynamic content'),
),
body: Column(
children: <Widget>[
//
RaisedButton(
child: Text('Add malt'),
onPressed: (){
Navigator.push(context, MaterialPageRoute(builder: (BuildContext context) => MaltInput()));
}
),
Text('Header.....'),
Text(maltpick),
Expanded(
child: ListView.builder(
itemCount: items.length,
itemBuilder: (BuildContext ctxt, int Index){
return Text(items[Index]);
}
),),
],
),
);
}
}
The error is in this line : builder: (context) => Test(malt[index]),
Error code: Error: Too many positional arguments: 0 allowed, but 1 found.
Try removing the extra positional arguments.
builder: (context) => Test(malt[index]),
If you use named parameters - the ones in {} - in your constructor
Test({this.malt});
you need to invoke it like this
MaterialPageRoute(builder: (context) => Test(malt: malt[index]))
You can check the documentation on the different kinds of parameters here.
Replace the below code.
class Test extends StatefulWidget {
String malt;
Test({this.malt});// here I Changed
#override
_TestState createState() => _TestState();
}
To
class Test extends StatefulWidget {
String malt;
Test(this.malt);// here it will be
#override
_TestState createState() => _TestState();
}
And remove String malt; and _TestState({this.malt}); code from test class.
class _TestState extends State<Test> {
String malt;// remove this line
_TestState({this.malt});// remove this line too
Related
I have managed to acquire and display data using CloudFireStore, but I would like to send the acquired data to the destination screen when the screen is transferred.
Navigator.push(
context,
MaterialPageRoute(builder: (context) => NextPage('test')),
));
but I don't know which function to put in.
↓This code is the one that sends the data.
class Rigakubu extends StatefulWidget {
const Rigakubu({Key? key}) : super(key: key);
#override
State<Rigakubu> createState() => _RigakubuState();
}
class _RigakubuState extends State<Rigakubu> {
final _firestore = FirebaseFirestore.instance;
List<DocumentSnapshot> documentList = [];
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('理学部'),),
body: SafeArea(
child: StreamBuilder(
stream: _firestore.collection('理学部').snapshots(),
builder:
(BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasError) {
return Center(
child:Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.do_disturb_on_outlined,size: 150,),
Text(
'校外のメールアドレスでログインしているため\nこの機能は利用できません。',
style: TextStyle(fontSize: 18),
textAlign: TextAlign.center,
),
],
)
);
}
if (!snapshot.hasData) {
return Center(
child: CircularProgressIndicator()
);
}
return ListView.builder(
itemCount: snapshot.data!.docs.length,
itemBuilder: (context, index){
return ListTile(
title: Text(snapshot.data!.docs[index].get('zyugyoumei')),
subtitle: Text(snapshot.data!.docs[index].get('kousimei')),
onTap: (){
Navigator.push(
context,
MaterialPageRoute(builder: (context) => View(post: snapshot.data!.docs)),
);
}
);
}
);
},
)
),
);
}
}
↓This code is the code on the receiving end of the data.
import 'package:flutter/material.dart';
import 'package:http/http.dart';
class View extends StatefulWidget {
final int post;
View(this.post);
const View({Key? key, required this.post}) : super(key: key);
#override
State<View> createState() => _ViewState();
}
class _ViewState extends State<View> {
late int state;
#override
void initState() {
super.initState();
// 受け取ったデータを状態を管理する変数に格納
state = widget.post;
}
#override
Widget build(BuildContext context) {
return Container(
child: Text(widget.post.bumon),
);
}
}
You could probably try this inside the onTap function before calling the Navigator
documentList = snapshot.data!.docs;
But generally avoid passing data through constructor and try to work with state management.
Record.dart
class Record extends StatefulWidget {
final List<String>? records;
const Record({
Key? key,
required this.records,
}) : super(key: key);
#override
_RecordState createState() => _RecordState();
}
class _RecordState extends State<Record> {
....
#override
Widget build(BuildContext context) {
return widget.records == null ? SizedBox() : ListView.builder(
itemCount: widget.records!.length,
shrinkWrap: true,
reverse: true,
itemBuilder: (BuildContext context, int i) {
return Card(
elevation: 5,
child: ExpansionTile(
...
record_body.dart
class record_Body extends StatefulWidget {
#override
_record_Body createState() => _record_Body();
static List<String>? records;
}
class _record_Body extends State<record_Body> {
List<String>? get record => video_Body.records;
...
before
Container(
height: 300,
child: IconButton(
onPressed: (){
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Record(
records: video_Body.records,
),
),
);
},
icon: Icon(Icons.mic, color: Colors.green, size: 45)
),
),
after
body: Obx(() {
switch(RouteName.values[controller.currentIndex.value]) {
case RouteName.Record:
return Record(records: video_Body.records); // error
Originally 'Record'(in record.dart) was loaded via navigator.push.
I want to load the listview using obx instead of navigator.push.
In my after, the listview is not visible. How do I solve this?
I m trying to pass arguments between pages but I m getting this error:
FlutterError (Could not find a generator for route RouteSettings("detail", Instance of 'Commodity') in the _WidgetsAppState.
Make sure your root app widget has provided a way to generate
this route.
Generators for routes are searched for in the following order:
For the "/" route, the "home" property, if non-null, is used.
Otherwise, the "routes" table is used, if it has an entry for the route.
Otherwise, onGenerateRoute is called. It should return a non-null value for any valid route not handled by "home" and "routes".
Finally if all else fails onUnknownRoute is called.
Unfortunately, onUnknownRoute was not set.)
I don't know why because 'detail' page already setted
This is my Main App
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
initialRoute: WelcomePage.routeName,
routes: {
'/welcome': (_) => const WelcomePage(),
'detail': (_) => SubCommoditiePage(),
},
);
}
}
This is my From Page
class DisplayOptions extends StatelessWidget {
final List<Commodity> _optionsToDisplay;
const DisplayOptions(this._optionsToDisplay);
#override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: _optionsToDisplay.length,
itemBuilder: (context, index) {
final opt = _optionsToDisplay[index];
return ListTile(
title: Text(opt.label),
subtitle: Text(opt.shortLabel),
onTap: () {
Navigator.pushNamed(context, 'detail', arguments: _optionsToDisplay[index]);
});
});
}
}
This is my Destination Page
class SubCommoditiePage extends StatefulWidget {
const SubCommoditiePage({Key? key}) : super(key: key);
static const String routenName = 'detail';
static Route route() {
return MaterialPageRoute(
builder: (_) => const SubCommoditiePage(),
settings: const RouteSettings(name: routenName));
}
#override
_SubCommoditiePageState createState() => _SubCommoditiePageState();
}
class _SubCommoditiePageState extends State<SubCommoditiePage> {
#override
Widget build(BuildContext context) {
final Commodity commoditySeleted =
ModalRoute.of(context)?.settings.arguments as Commodity;
return Scaffold(
appBar: AppBar(
title: Text(commoditySeleted.label),
),
);
}
}
For initial/homepage, use /. In this case your WelcomePage.routeName will be /;
and route
routes: {
WelcomePage.routeName: (_) => WelcomePage(),
..........
},
You don't need to pass initialRoute while the root '/' will be selected.
For more about named-routes
The way I was able to solve it was:
I evidently didn't know why flutter didn't recognize my 'detail' page.
And I had to do it this way:
This is my From Page
in my ontap, I used
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SubCommoditiePage(
seleted: _optionsToDisplay[index],
)));
like that:
class DisplayOptions extends StatelessWidget {
final List<Commodity> _optionsToDisplay;
const DisplayOptions(this._optionsToDisplay);
#override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: _optionsToDisplay.length,
itemBuilder: (context, index) {
final opt = _optionsToDisplay[index];
return ListTile(
title: Text(opt.label),
subtitle: Text(opt.shortLabel),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SubCommoditiePage(
seleted: _optionsToDisplay[index],
)));
});
});
}
}
adding to my page: final Commodity seleted; and with widget.selected... I was able to use it perfectly!
class SubCommoditiePage extends StatefulWidget {
final Commodity seleted;
const SubCommoditiePage({required this.seleted, Key? key}) : super(key: key);
static const String routenName = 'detail';
#override
_SubCommoditiePageState createState() => _SubCommoditiePageState();
}
class _SubCommoditiePageState extends State<SubCommoditiePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.seleted.label),
backgroundColor: const Color.fromRGBO(37, 59, 128, 5),
),
body: ListView.builder(
itemCount: widget.seleted.subCommodities.length,
itemBuilder: (context, index) {
final opt = widget.seleted.subCommodities[index];
return ListTile(
title: Text(opt.label),
onTap: () {},
);
}));
}
}
So I'm trying to make a list that contains some widgets and then add a new widget to it when I press a button, but it doesn't seem to be working
This is the code:
class MessagesProvider extends ChangeNotifier{
List<dynamic> mesgs = [
new chatBubbleSend(),
new chatBubbleReceiver(),
new chatBubbleReceiver()
];
bool loading = true;
addMesg(){
mesgs.add(chatBubbleSend());
print(mesgs.length);
print(mesgs);
notifyListeners();
}
printMesg(){
print(mesgs.length);
print(mesgs);
}
removeMesg(){
mesgs.removeLast();
print(mesgs.length);
print(mesgs);
notifyListeners();
}
}
and this is what i get when i press the add, remove or print buttons
add,remove,print
and this is the list builder code
ChangeNotifierProvider<MessagesProvider>(
create: (context) => MessagesProvider(),
child: ChatMessages()
),
class ChatMessages extends StatelessWidget {
#override
Widget build(BuildContext context) {
final mesgs = Provider.of<MessagesProvider>(context, listen: false).mesgs;
return ListView.builder(
shrinkWrap: true,
itemCount: mesgs.length,
itemBuilder: (context,index)=> mesgs[index],
);
}
}
I have looking for a solution for over 8 hours now, and still, I couldn't fix it.
I jumped the gun with my first answer sorry.
When trying to recreate I ran into the same frustrating issue - focusing on the the provider being the problem until I realised it's actually the rendering of the updated list that's the issue.
You need to use a list builder to render the updating list in a change notifier consumer in a stateful widget
Full working example below:
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class WidgetListProvider with ChangeNotifier {
List<Widget> widgets = [];
int listLength = 0;
void addWidget(){
Widget _widget = Text('Hello');
widgets.add(_widget);
listLength = widgets.length;
print('Added a widget');
notifyListeners();
}
void removeWidget(){
if (widgets.length > 0) {
widgets.removeLast();
listLength = widgets.length;
print('Removed a widget');
notifyListeners();
}
}
}
class HomePage extends StatefulWidget {
HomePage({Key key}) : super(key: key);
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
Widget _appBar (BuildContext context) {
return AppBar(
title: Text('My App'),
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: _appBar(context),
// You need to define widgets that update when a provider changes
// as children of a consumer of that provider
body: Consumer<WidgetListProvider>(builder: (context, widgetProvider, child){
return Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [
RaisedButton(
child: Text('Add widget'),
onPressed: () {
widgetProvider.addWidget();
},
),
RaisedButton(
child: Text('Remove Widget'),
onPressed: () {
widgetProvider.removeWidget();
},
),
Row(
children: [
Text('Number of Widgets: '),
Text(widgetProvider.listLength.toString()),
],
),
Container(
height: MediaQuery.of(context).size.height*0.6,
child: ListView.builder(itemCount: widgetProvider.widgets.length, itemBuilder: (BuildContext context, int index){
return widgetProvider.widgets[index];
})
)
],
),
);
}
),
);
}
}
void main() {
runApp(
ChangeNotifierProvider(
create: (context) => WidgetListProvider(),
child: MyApp(),
)
);
}
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'My App',
home: HomePage(),
);
}
}
I am trying to navigate to a page called contactView. I have made a list of contacts and I wait to navogate to a contact when I click on there name. This is what I have so far. I am stuck trying to get the navigation to work. Any help would be great.
class ContactList extends StatelessWidget {
final List<Contact> _contacts;
ContactList(this._contacts);
#override
Widget build(BuildContext context) {
return new ListView.builder(
padding: new EdgeInsets.symmetric(vertical: 8.0),
itemBuilder: (context, index) {
return new _ContactListItem(_contacts[index]);
Navigator.push(context, MaterialPageRoute(builder: (context) => viewContact())
);
},
itemCount: _contacts.length,
);
}
}
Here are few things that I can immediately point out (Problems):
onPressed is not available on ListView.builder() , you may check
here:
https://docs.flutter.io/flutter/widgets/ListView/ListView.builder.html
Navigator.push(context, MaterialPageRoute(builder: (context) => viewContact()) this won't execute because it is after return
Suggestions:
You might need to wrap your _ContactListItem() inside a
GestureDetector and implement an onTap callback
Sample Code:
class ContactList extends StatelessWidget {
final List<Contact> _contacts;
ContactList(this._contacts);
#override
Widget build(BuildContext context) {
return ListView.builder(
padding: EdgeInsets.symmetric(vertical: 8.0),
itemBuilder: (context, index) {
return GestureDetector(
onTap: () {
//TODO: Insert your navigation logic here
Navigator.of(context).push(MaterialPageRoute(
builder: (BuildContext context) =>
ContactView(_contacts[index])));
},
child: _ContactListItem(_contacts[index]),
);
},
itemCount: _contacts.length,
);
}
}
Another option could be to change the implementation of
_ContactListItem() and may be use a ListTile and implement an onTap in ListTile, you can find it here: https://docs.flutter.io/flutter/material/ListTile-class.html
You may also try to implement named routes, here is a tutorial for
that https://flutter.io/cookbook/networking/named-routes/
I hope this was helpful in someway, let me know if I misinterpreted the question.
See if the below is what you're looking for.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Contact Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Contact Demo'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final _contacts = [
Contact(name: 'John'),
Contact(name: 'Mary'),
Contact(name: 'Suzy')
];
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: null,
title: const Text(
'Contact Demo',
style: const TextStyle(color: Colors.white),
),
),
body: ListView.builder(
itemCount: _contacts.length,
itemBuilder: (BuildContext context, int index) {
return ListTile(
title: Text('Contact #$index'),
onTap: () {
Navigator.of(context).push(MaterialPageRoute<void>(
builder: (BuildContext context) =>
ContactView(contact: _contacts[index]),
));
},
);
},
),
);
}
}
class Contact {
Contact({this.name});
final String name;
}
class ContactView extends StatelessWidget {
ContactView({this.contact});
final Contact contact;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(contact.name),
),
body: Center(
child: Text(contact.name),
),
);
}
}