what is the different between Function first class and void function in Dart - flutter

in order to optimize my code, I try to use Function first class in the onTap property of the GestureDetector widget, like in the code below:
import 'package:flutter/material.dart';
class ReusableCard extends StatelessWidget {
final Color colour;
final Widget? childCard;
final Function? onPress;
ReusableCard({required this.colour,this.childCard,this.onPress}) ;
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: onPress,
child: Container(
child: childCard,
margin: EdgeInsets.all(15.0),
decoration: BoxDecoration(
color: colour,
borderRadius:BorderRadius.circular(10.0),
),
),
);
}
}
but I got that error: The argument type 'Function?' can't be assigned to the parameter type 'void Function()?'.
hope that someone can explain what going on here and thank you previously.

Use VoidCallback? in this case instead of Function?.
In the end, VoidCallback is defined as typedef VoidCallback = void Function() so you can even end up using Function()? but this is a cool shortcut.

You need to use Function()? instead of Function? as the type of onPress variable because onTap requires a GestureTapCallback which is typedef for a Function().
class ReusableCard extends StatelessWidget {
final Color colour;
final Widget? childCard;
final Function()? onPress;
ReusableCard({required this.colour, this.childCard, this.onPress});
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: onPress,
child: Container(
child: childCard,
margin: EdgeInsets.all(15.0),
decoration: BoxDecoration(
color: colour,
borderRadius: BorderRadius.circular(10.0),
),
),
);
}
}

Related

I'm trying to create a optional parameter in constructor but still getting error, can any one help me with that?

class ReusableCard extends StatelessWidget {
ReusableCard({required this.colour, this.cardChild});
final Color colour;
final Widget cardChild;
#override
Widget build(BuildContext context) {
return Container(
margin: const EdgeInsets.all(15.0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10.0),
color: colour,
),
// child: cardChild,
);
}
}
This is the error :
" The parameter 'cardChild' can't have a value of 'null' because of its type, but the implicit default value is 'null'. "
I don't know what your cardChild code is, but I think the answer you are looking for is this.
class ReusableCard extends StatelessWidget {
final Color colour;
final Widget? cardChild;
ReusableCard({required this.colour, this.cardChild});
#override
Widget build(BuildContext context) {
return Container(
margin: const EdgeInsets.all(15.0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10.0),
color: colour,
),
child: cardChild ?? SizedBox(),
);
}
}
class ReusableCard extends StatelessWidget {
final Color colour;
final Widget? cardChild; -------> just add ? for making parameter optional
ReusableCard({required this.colour, this.cardChild});
class ReusableCard extends StatelessWidget {
final Color colour;
final Widget cardChild;
//define the variable 1st
//then call the method
ReusableCard({required this.colour, this.cardChild});
#override
Widget build(BuildContext context) {
return Container(
margin: const EdgeInsets.all(15.0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10.0),
color: colour,
),
// child: cardChild,
);
}
}
class ReusableCard extends StatelessWidget {
final Color colour;
final Widget cardChild;
//define the variable 1st
//then call the method
ReusableCard({required this.colour, this.cardChild});
#override
Widget build(BuildContext context) {
return Container(
margin: const EdgeInsets.all(15.0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10.0),
color: colour,
),
// child: cardChild,
);
}
}

How do i pass a function as a parameter in dart?

Code down here keeps telling me that there's a problem in the syntax here onTap: onPress,
import 'package:flutter/material.dart';
class ReusableCard extends StatelessWidget {
final Color color;
final Widget? cardChild;
final Function? onPress;
ReusableCard({ this.cardChild, required this.color, this.onPress});
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: onPress,
child: Container(
margin: const EdgeInsets.all(15.0),
decoration: BoxDecoration(
color: color,
borderRadius: BorderRadius.circular(15.0),
),
child: cardChild,
),
);
}
}
Use voidcallback
class ReusableCard extends StatelessWidget {
final Color color;
final Widget? cardChild;
final VoidCallback onPress;//here
ReusableCard({ this.cardChild, required this.color, this.onPress});
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: onPress,
child: Container(
margin: const EdgeInsets.all(15.0),
decoration: BoxDecoration(
color: color,
borderRadius: BorderRadius.circular(15.0),
),
child: cardChild,
),
);
}
}
or you can also do this
class ReusableCard extends StatelessWidget {
final Color color;
final Widget? cardChild;
final Function? onPress;
ReusableCard({ this.cardChild, required this.color, this.onPress});
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: (){onPress();},//create a method and call onPress here
child: Container(
margin: const EdgeInsets.all(15.0),
decoration: BoxDecoration(
color: color,
borderRadius: BorderRadius.circular(15.0),
),
child: cardChild,
),
);
}
}
Function is null type, so it can be null.
You should write
onTap:(onPress!=null) ? onPress : null
Using final Function? onPress; is defined nullable function.
But onTap requires void function,
You can just do
final Function()? onPress;
Or
onTap: () {
if (onPress != null) onPress!();
},
Using VoidCallback
/// Signature of callbacks that have no arguments and return no data.
typedef VoidCallback = void Function();
Hope you get the issue here. Also provide key on constructor.
class ReusableCard extends StatelessWidget {
final Color color;
final Widget? cardChild;
final Function()? onPress;
const ReusableCard({
this.cardChild,
required this.color,
this.onPress,
super.key,
});
But I think it is pretty to use final GestureTapCallback? onPress;

'Function?' can't be assigned to the parameter type 'void Function()?

import 'package:flutter/material.dart';
class ReusableCard extends StatelessWidget {
final Color? colour;
final Widget? cardChild;
final Function? onPress;
ReusableCard({this.colour, this.cardChild, this.onPress});
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: **onPress**,
child: Container(
child: cardChild,
margin: EdgeInsets.all(15.0),
decoration: BoxDecoration(
color: colour,
borderRadius: BorderRadius.circular(10.0)),
),
);
}
}
lib/reusable_card.dart:15:14: Error: The argument type 'Function?' can't be assigned to the parameter type 'void Function()?'.
'Function' is from 'dart:core'.
onTap: onPress,
^
What could be the error and how should I use the function onPress instead?
Use VoidCallback? instead like so: final VoidCallback? onPress;
Or use final void Function()? onPress;

Stateless widget with required and optional values with null safety

So I am trying to create a custom widget I can use in my flutter app. When creating this widget I want to always select a color (hence the required value) but I want to keep the cardChild and onpres values optional. How do I do this? I tried to give a empty Container and empty function as default values but then I get the errror
error: The default value of an optional parameter must be constant.
(non_constant_default_value at [untitled1]
lib/Components/reusable_card.dart:6)
here is my widget constructor:
class ReusableCard extends StatelessWidget {ReusableCard(
{required this.colour, this.cardChild = Container(), this.onPress = () {}});
final Color colour;
final Widget cardChild;
final Function onPress;
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
onPress;
},
child: Container(
child: cardChild,
margin: EdgeInsets.all(15.0),
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(15.0)),
color: colour,
),
),
);
}
}
you can use following approach
class ReusableCard extends StatelessWidget {ReusableCard(
{required this.colour, this.cardChild, this.onPress});
final Color colour;
final Widget? cardChild;
final Function? onPress;
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
if(onPress != null){
onPress!();
}
},
child: Container(
child: cardChild ?? Container(),
margin: EdgeInsets.all(15.0),
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(15.0)),
color: colour,
),
),
);
}
}
You can do it either by making cardChild and onPress positional parameter in the constructor.
class ReusableCard extends StatelessWidget {
//constructor
ReusableCard(this.colour,this.cardChild, this.onPress);
final Color colour;
final Widget cardChild;
final Function onPress;
#override
Widget build(BuildContext context) {
....
or make them nullable by adding ?:
class ReusableCard extends StatelessWidget {
//constructor
ReusableCard({required this.colour, this.cardChild, this.onPress});
final Color colour;
final Widget? cardChild;
final Function? onPress;
#override
Widget build(BuildContext context) {
....
For better understanding about named and positional parameters read this.

The argument type 'Function?' can't be assigned to the parameter type 'void Function()?

this is the screenshot of my error code
this code my inputpage:
child: ReusableCard(
onPress: (){
setState(() {
selectGender=Gender.male;
});
},
cardChild: IconContent(icon: FontAwesomeIcons.mars,label: 'Male',),
colour: selectGender==Gender.male? activeCardColor:inactivecolor,
),
and this one other page:onpress function does not work.
class ReusableCard extends StatelessWidget {
ReusableCard({#required this.colour,this.cardChild,this.onPress});
final Color? colour;
final Widget? cardChild;
final Function? onPress;
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: onPress,
child: Container(
child: cardChild,
margin: EdgeInsets.all(15),
decoration: BoxDecoration(
color: colour,
borderRadius: BorderRadius.circular(10.0),
),
),
);
}
}
i provide screesshoot for your better understand
Because the widget's onTap is defined as a void Function()? onTap, the value needs to be returned to be used (as a callback). So use:
onTap: ()=> onPress,
You can also define the onPress as a VoidCallback?, then you just need to:
onTap: onPress,
change this line
final Function? onPress;
with
final Function() onPress;
class ReusableCard extends StatelessWidget {
ReusableCard({#required this.colour,this.cardChild,this.onPress});
final Color? colour;
final Widget? cardChild;
final Function? onPress;
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: onPress, // the problem is here
child: Container(
child: cardChild,
margin: EdgeInsets.all(15),
decoration: BoxDecoration(
color: colour,
borderRadius: BorderRadius.circular(10.0),
),
),
);
}
}
Change this to That:
class ReusableCard extends StatelessWidget {
ReusableCard({#required this.colour,this.cardChild,this.onPress});
final Color? colour;
final Widget? cardChild;
final Function? onPress;
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap:(){
--add your on press code here
},
child: Container(
child: cardChild,
margin: EdgeInsets.all(15),
decoration: BoxDecoration(
color: colour,
borderRadius: BorderRadius.circular(10.0),
),
),
);
}
}
Just replace like below.
From
onTap: onPress,
To
onTap: () => onPress,
class ReusableCard extends StatelessWidget {
ReusableCard({#required this.colour,this.cardChild,this.onPress});
final Color? colour;
final Widget? cardChild;
final Function? onPress;
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () => onPress,
child: Container(
child: cardChild,
margin: EdgeInsets.all(15),
decoration: BoxDecoration(
color: colour,
borderRadius: BorderRadius.circular(10.0),
),
),
);
}
}
I got the same issue, this is the way I solved it:
Instead of
final Function? onPress;
Use this:
final VoidCallback? onPress;