Working on an App that will require multiple screens. The below right now shows only two icons, more later, and i need them the be able to go the a corresponding screen when pressed. Everything works but the onPressed function. The error I get is
The named parameter "onPressed" is not defined
Do I have the onPressed function in the wrong spot? I have tried moving it between other functions but I get the same error.
Any help is appreciated
main.dart
import 'package:flutter/material.dart';
import './food_screen.dart';
void main(List<String> args) {
runApp(new MaterialApp(
home : MyApp(),
));
}
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: new AppBar(
title :Text('Main Title'),
backgroundColor: Colors.blue,
),
backgroundColor: Colors.blue[100],
body: Container(
padding: EdgeInsets.all(30.0),
child: GridView.count(
crossAxisCount: 2,
children: <Widget>[
Card(
margin: EdgeInsets.all(8.0),
child: InkWell(
onTap: (){
Navigator.push(context,
MaterialPageRoute(builder: (context)=>FoodScreen())
);
},
splashColor: Colors.blue,
child: Center(
child: Column(
children: <Widget>[
Icon(Icons.fastfood, size: 70.0),
Text("FOOD", style: new TextStyle(fontSize: 28.0))
]
)
),
),
),
Card(
margin: EdgeInsets.all(8.0),
child: InkWell(
onTap: (){},
splashColor: Colors.blue,
child: Center(
child: Column(
children: <Widget>[
Icon(Icons.directions_car, size: 70.0),
Text("VEHILCES", style: new TextStyle(fontSize: 28.0))
],
),
),
),
),
]
)
)
);
}
}
food_screen.dart
import 'package:flutter/material.dart';
import './main.dart';
class FoodScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Second Screen"),
),
);
}
}
Card doesn't support onPressed property, you already have InkWell which has onTap, you can put onPressed method action inside it.
onTap: () {
Navigator.push(context,
MaterialPageRoute(builder: (context)=>FoodScreen())
);
}
Card doesn't have any property of onpressed()
you can add a floating button and Route it to the the second page i.e food_screen.dart
https://api.flutter.dev/flutter/material/Card-class.html
if you want to add a tap on Card Widget just wrap the card with GestureDetector.
Related
For example:
// Update: This GestureDetector is embedded inside a third party package
// that will invoke a series of animation along with the onTap button
GestureDetector(
onTap: () => print('Hey There!'),
child: Widget1(),
)
// Then another place in the same screen
GestureDetector(
onDoubleTap: () {
//Call the onTap of Widget1's GestureDetector
print('I'm Here');
}
child: Widget2(),
)
What I wanted is when a user double tap Widget2, it will also invoke the onTap call back of Widget1.
Update:
So I do not want to just invoke a function passed into the onTap of GestureDetector of Widget1, but rather to programmatically tap the onTap of Widget1's GestureDetector
How do I do that?
You can do something like this -
Create your gesture detector -
GestureDetector gestureDetector = GestureDetector(
onTap: () {
setState(() {
_lights = !_lights;
});
},
child: Container(
color: Colors.yellow.shade600,
padding: const EdgeInsets.all(8),
child: const Text('TURN LIGHTS ON'),
),
);
Create a button (or any widgetthat you would like to use) to call onTap on GestureDetector gestureDetector.onTap() just like you call method on another widget. (I am using a FlatButton here)-
FlatButton(
color: Colors.blue,
textColor: Colors.white,
disabledColor: Colors.grey,
disabledTextColor: Colors.black,
padding: EdgeInsets.all(8.0),
onPressed: () {
//Trigger the GestureDetector onTap event.
gestureDetector.onTap();
},
child: Text("Click Here"),
),
Now you can click on the FlatButton to call the onTap event on GestureDetector.
Here is the complete example -
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Gesture Detector On Tap'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
bool _lights = false;
#override
Widget build(BuildContext context) {
GestureDetector gestureDetector = GestureDetector(
onTap: () {
setState(() {
_lights = !_lights;
});
},
child: Container(
color: Colors.yellow.shade600,
padding: const EdgeInsets.all(8),
child: const Text('TURN LIGHTS ON'),
),
);
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Container(
alignment: FractionalOffset.center,
color: Colors.white,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: Icon(
Icons.lightbulb_outline,
color: _lights ? Colors.yellow.shade600 : Colors.black,
size: 60,
),
),
gestureDetector,
SizedBox(height: 50.0),
FlatButton(
color: Colors.blue,
textColor: Colors.white,
disabledColor: Colors.grey,
disabledTextColor: Colors.black,
padding: EdgeInsets.all(8.0),
onPressed: () {
gestureDetector.onTap();
},
child: Text("Click Here"),
),
],
),
),
),
);
}
}
You will get something like this -
Update: So I do not want to just invoke a function passed into the onTap of GestureDetector of Widget1, but rather to programmatically tap the onTap of Widget1's GestureDetector
The purpose of onTap is to call the callback function inside the onTap. So I'm not sure why you just want to tap the button other than invoking functions that should be called when tapping that button (Can you elaborate on this?).
If you want to simulate the tap for testing, you can do that with Flutter Driver using driver.tap()
After several false starts, this is what worked for me. I use Riverpod, and formFocusIdProvider in this example code is a simple StateProvider.
I'm actually not clear why I needed to add the delay - but without that the behavior was unpredictable with the widget repaint.
This code is in the build method.
ref.listen(formFocusIdProvider, (previous, next) {
if (<some condition>) {
Future.delayed(const Duration(milliseconds: 200), () {
if (mounted) {
onTapFunction();
}
});
}
});
just make the first one's function separately
void firstFunction(){
print('hey There!');
}
like this, then call it in the second widget
so your code will look like this:
GestureDetector(
onTap: () => firstFunction(),
child: Widget1(),
)
// Then another place in the same screen
GestureDetector(
onDoubleTap: () {
firstFunction();
print('I'm Here');
}
child: Widget2(),
)
I am new to Flutter and I am following Flutter's official tutorial to learn basics of flutter.
So, I want to create a reusable component named "CustomCard" and I did this:
class CustomCard extends StatelessWidget {
CustomCard({#required this.index, #required this.onPress});
final index;
final Function onPress;
#override
Widget build(BuildContext context) {
return Card(
child: Column(
children: <Widget>[
Text('Card $index'),
FlatButton(
child: const Text('Press'),
onPressed: this.onPress,
)
],
),
);
}
}
Now, to use it in MyApp, I did this:
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: 'Welcome to flutter',
home: Scaffold(
appBar: AppBar(
title: Text('hello'),
),
body: Center(
child: Text('centre'),
CustomCard(
index:'card1',
onPress: print(' this is $index')
),
),
),
);
}
}
Now my IDE says that:
The method 'CustonCard' isn't defined for the class 'MyApp'.
How to solve this?
Error in terminal:
Compiler message:
lib/main.dart:17:6: Error: Place positional arguments before named arguments.
Try moving the positional argument before the named arguments, or add a name to the argument.
CustomCard(
^^^^^^^^^^
lib/main.dart:17:6: Error: Expected named argument.
CustomCard(
^
lib/main.dart:15:21: Error: No named parameter with the name '#1'.
body: Center(
^^...
/C:/src/flutter/packages/flutter/lib/src/widgets/basic.dart:1863:9: Context: Found this candidate, but the arguments don't match.
const Center({ Key key, double widthFactor, double heightFactor, Widget child })
Edit: corrected a spelling mistake. Also adding console log.
You have got a few mistakes going on, but don't worry it happens at the very beginning. So let's step into the problems:
First, inside the body you've defined a Center Widget which only allows a single child within it but you have tried to put two Widgets (Text and CustomCard). So to put both widgets you could change it to something like this:
Center(
child: Column(
children: <Widget>[
Text('centre'),
CustomCard(...)
],
),
),
Moreover, pay attention that the onPress function takes a Function as argument but you are passing the result of print(...) which is void. Simply change it to:
CustomCard(index: index, onPress: () => print(' this is $index'))
Finally, I think you missed to define the index variable. Simply add:
String index = "card1";
Hey Please check the updated code here. There are couple of compile errors as you are wrapping up both Text and you CustomWidget in Center where it accepts only one child widget and also at the onPress method some code change required.
import 'package:flutter/material.dart';
final Color darkBlue = Color.fromARGB(255, 18, 32, 47);
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Welcome to flutter',
home: Scaffold(
appBar: AppBar(
title: Text('hello'),
),
body: Center(
child:Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('centre'),
CustomCard(
index:'card1',
onPress: onPress
)
],
)
)
),
);
}
onPress(index){
print("this is $index");
}
}
class CustomCard extends StatelessWidget {
CustomCard({#required this.index, #required this.onPress});
final index;
final Function onPress;
#override
Widget build(BuildContext context) {
return Card(
child: Column(
children: <Widget>[
Text('Card $index'),
FlatButton(
child: const Text('Press'),
onPressed: (){
this.onPress(index);
},
)
],
),
);
}
}
child: Center(
child: Row(
children: <Widget>[
_box(), //Custom pin view
_box(), //Custom pin view
_box(), //Custom pin view
_box(),//Custom pin view
],
),
)
and Custom Widgets (_box) Code
Widget _box() {
return Container(
margin: EdgeInsets.symmetric(vertical: 5, horizontal: 3),
alignment: Alignment.center,
height: 50,
width: 50,
child: TextField(
keyboardType: TextInputType.number,
maxLength: 1,
decoration: InputDecoration(border: InputBorder.none, counterText: ''),
),
decoration: BoxDecoration(border: Border.all(color: Colors.blue)),
);
}
I have issue with the Raised button click. The method inside OnPressed() is not getting called. Ideally on the OnPressed() method i would like to have the pop up or a slider shown. I have created the example to show the problem currently faced.
The main.dart file calls Screen2()
import 'package:flutter/material.dart';
//import 'package:flutter_app/main1.dart';
import 'screen2.dart';
void main() => runApp(Lesson1());
class Lesson1 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Screen2(),
);
}
}
and in Screen2()i have just have a RaisedButton and OnPressed() it needs to call the function ButtonPressed().
import 'package:flutter/material.dart';
class Screen2 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.blue,
title: Text('Screen 2'),
),
body: Center(
child: RaisedButton(
color: Colors.blue,
child: Text('Go Back To Screen 1'),
onPressed: () {
print('centrebutton');
ButtonPressed();
},
),
),
);
}
}
class ButtonPressed extends StatefulWidget {
#override
_ButtonPressedState createState() => _ButtonPressedState();
}
class _ButtonPressedState extends State<ButtonPressed> {
#override
Widget build(BuildContext context) {
print ('inside button press');
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.red,
title: Text('Screen 3'),
),
// create a popup to show some msg.
);
}
}
On clicking the Raised button the print statement ('centerbutton') gets printed.
But the ButtonPressed() method is not getting called .
I am not able to see the print msg('inside button press') in the console. Pl. let me what could be the reason for ButtonPressed method not getting called. Attached the snapshot for your reference.
You are calling a Widget on your RaisedButton's onPressed method. Your widget is getting called but will not render anywhere in the screen.
You should call a function for processing your data in a tap event. But you are calling a widget or say a UI view.
If you want to navigate to the respective screen then you should use navigator.
For ex :
onPressed: () {
print('centrebutton');
Navigator.push(context, MaterialPageRoute(builder: (BuildContext context) => ButtonPressed()));
},
This could be a cause: If you have an asset as a child of your button, and that asset does not exist, the button onpressed will not work.
Solution: remove the asset.
Example:
return RaisedButton(
splashColor: Colors.grey,
onPressed: () {
},
child: Padding(
padding: const EdgeInsets.fromLTRB(0, 10, 0, 10),
child: Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Image(image: AssetImage("assets/google_logo.png"), height: 35.0), //remove this line
Padding(
padding: const EdgeInsets.only(left: 10),
child: Text(
'Sign in with Google',
style: TextStyle(
fontSize: 20,
color: Colors.grey,
),
),
)
],
),
),
);
I want to open a drawer after pushing on the custom button in BottomMenu I have trouble with Scaffold.of(context).openDrawer(), it doesn't work. My BottomMenu is a separate widget class. As I understand, it doesn't work because it's a separate context. How can I get the right context? Or perhaps someone knows another solution.
Here my code reproducer:
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',
home: MyHomePage(title: 'Flutter Drawer'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
bottomNavigationBar: BottomMenu(),
endDrawer: SizedBox(
width: double.infinity,
child: Drawer(
elevation: 16,
child: Container(
color: Colors.black,
child: ListView(
padding: EdgeInsets.zero,
children: <Widget>[
ListTile(
title: Text('Some context here',
style: TextStyle(color: Colors.white))),
ListTile(
title: Text('Some context here',
style: TextStyle(color: Colors.white))),
],
),
),
),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'Call Drawer form menu reproducer',
)
],
),
),
);
}
}
class BottomMenu extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 15),
child: Wrap(
alignment: WrapAlignment.center,
children: <Widget>[
Divider(color: Colors.black, height: 1),
Padding(
padding: const EdgeInsets.symmetric(vertical: 2),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
InkWell(
borderRadius: new BorderRadius.circular(20.0),
customBorder: Border.all(color: Colors.black),
child: Container(
padding: EdgeInsets.only(
left: 3, right: 6, bottom: 15, top: 11),
child: Row(
children: <Widget>[
Icon(Icons.menu),
Text('Show menu', style: TextStyle(fontSize: 15, fontWeight: FontWeight.bold)),
],
),
),
onTap: () {
Scaffold.of(context).openDrawer();
},
),
],
),
),
],
),
);
}
}
In my case, this worked.
return Scaffold(
key: _scaffoldKey,
endDrawerEnableOpenDragGesture: false, // This!
appBar: AppBar(
iconTheme: IconThemeData(color: Colors.white),
leading: IconButton(
icon: Icon(Icons.menu, size: 36),
onPressed: () => _scaffoldKey.currentState.openDrawer(), // And this!
),
),
drawer: DrawerHome(),
....
and _scaffoldKey must be initialized as,
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
under the class.
The problem is that you specified endDrawer on Scaffold yet you're calling Scaffold.of(context).openDrawer().
openDrawer() documentation states:
If the scaffold has a non-null Scaffold.drawer, this function will cause the drawer to begin its entrance animation.
Since your drawer is null, nothing happens.
In contrast, openEndDrawer() informs us:
If the scaffold has a non-null Scaffold.endDrawer, this function will cause the end side drawer to begin its entrance animation.
Since your endDrawer is not null you should use openEndDrawer() method. Alternatively, if you don't care which side the drawer slides in from, you can use drawer instead of endDrawer when building Scaffold.
My problem solved that instead of
Scaffold.of(context).openEndDrawer()
I give key to Scaffold and then I call by state like below
_scaffoldkey.currentState.openEndDrawer()
It solved my problem I hope It also works for you
Scaffold.of(context).openEndDrawer()
The Problem
This issue can occur when you do not use the correct BuildContext when calling Scaffold.of(context).openDrawer() (or openEndDrawer()).
Easiest Solution
Simply wrap whatever calls openDrawer() (or openEndDrawer()) with a Builder widget. This will give it a working context.
Minimal Working Example
// your build method
#override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: Builder(builder: (context) { // this uses the new context to open the drawer properly provided by the Builder
return FloatingActionButton(onPressed: (() => Scaffold.of(context).openDrawer()));
}),
drawer: const Drawer(
child: Text("MY DRAWER"),
),
);
}
Similar problem here. Clicked on button and nothing happened. The problem is I was using the context of the widget that instantiated Scaffold. Not the context of a child of Scaffold.
Here is how I solved it:
// body: Column(
// children: <Widget>[
// Row(
// children: <Widget>[
// IconButton(
// icon: Icon(Icons.filter_list),
// onPressed: () => Scaffold.of(context).openEndDrawer(), (wrong context)
// ),
// ],
// ),
// ],
// )
To:
body: Builder(
builder: (context) => Column(
children: <Widget>[
Row(
children: <Widget>[
IconButton(
icon: Icon(Icons.filter_list),
onPressed: () => Scaffold.of(context).openEndDrawer(),
),
],
),
],
)),
),
Assign Drawer to drawer property in scaffold. Wrap your specific Widget/Button(where you want to open drawer on its click method) with Builder. Use below method on click property:
enter image description here
Scaffold.of(context).openDrawer();
If you have the appbar widget with an action button to launch the drawer and the drawer is never pushed please remember that you need to define after appbar: ... the endDrawer: YOURAppDrawerWIDGET(), or else using the Scaffold.of(context).openEndDrawer() will not work.
Scaffold(
appBar: AppBar(title: Text(_title)),
endDrawer: AppDrawer(), // <-- this is required or else it will not know what is opening
body: SingleChildScrollView(
///...
I have this problem with actions of AlertDialog
AlertDialog(
title: ...,
content: ...,
actions: <Widget>[
FlatButton(onPressed: ...,
child: Text(btn_download)),
FlatButton(onPressed: ...,
child: Text('btn_select')),
FlatButton(onPressed: ...,
child: Text(btn_qr)),
FlatButton(onPressed: ...,
child: Text(btn_cancel)),
],
);
When I show this dialog I get this:
I tried to use Wrap or other scrolling and multi-child widets, but nothing helps.
Found the same issue here, but no answer yet
Does anybody knows how this can be fixed?
I don't have access to AndroidStudio to validate my hypothesis, but I'd try something like this:
AlertDialog(
title: ...,
content: ...,
actions: <Widget>[
new Container (
child: new Column (
children: <Widget>[
FlatButton(onPressed: ...,
child: Text(btn_download)),
FlatButton(onPressed: ...,
child: Text('btn_select'))
),
new Container (
child: new Column (
children: <Widget>[
FlatButton(onPressed: ...,
child: Text(btn_gr)),
FlatButton(onPressed: ...,
child: Text('btn_cancel'))
),
),
],
);
Edit: this code works, but you have to use a width-constrained Container, even though it seems that a 75% screen width is somewhat of a sweet spot, since it works both in portrait and landscape mode.
import 'package:flutter/material.dart';
import 'dart:async';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
Future<Null> _neverSatisfied() async {
double c_width = MediaQuery.of(context).size.width*0.75;
return showDialog<Null>(
context: context,
barrierDismissible: false, // user must tap button!
builder: (BuildContext context) {
return new AlertDialog(
title: new Text('Rewind and remember'),
content: new SingleChildScrollView(
child: new ListBody(
children: <Widget>[
new Text('You will never be satisfied.'),
new Text('You\’re like me. I’m never satisfied.'),
],
),
),
actions: <Widget>[
new Container(
width: c_width,
child: new Wrap(
spacing: 4.0,
runSpacing: 4.0,
children: <Widget>[
new FlatButton(
child: new Text('The Lamb'),
onPressed: () {
Navigator.of(context).pop();
},
),
new FlatButton(
child: new Text('Lies Down'),
onPressed: () {
Navigator.of(context).pop();
},
),
new FlatButton(
child: new Text('On'),
onPressed: () {
Navigator.of(context).pop();
},
),
new FlatButton(
child: new Text('Broadway'),
onPressed: () {
Navigator.of(context).pop();
},
),
],
)
)
],
);
},
);
}
void _doNeverSatisfied() {
_neverSatisfied()
.then( (Null) {
print("Satisfied, at last. ");
});
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(widget.title),
),
body: new Center(
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Text(
'You have pushed the button this many times:',
),
new Text(
'$_counter',
style: Theme.of(context).textTheme.display1,
),
],
),
),
floatingActionButton: new FloatingActionButton(
onPressed: _doNeverSatisfied,
tooltip: 'Call dialog',
child: new Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
The ButtonBar is not made for so many buttons.
Place your buttons in a Wrap widget or a Column.