167

I want to achieve to make a drawer with different items on it, so I am creating a separate file for the DrawerItems and the with the constructor, pass the data to the main file. But I get the following error on the onPressed function:

"The argument type 'Function' can't be assigned to the parameter type 'void Function()'"
class DrawerItem extends StatelessWidget {
    
      final String text;
      final Function onPressed;
    
      const DrawerItem({Key key, this.text, this.onPressed}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return FlatButton(
          child: Text(
            text,
            style: TextStyle(
              fontWeight: FontWeight.w600,
              fontSize: 18.0,
            ),
          ),
          onPressed: onPressed,
        );
      }
    }

Anyone knows why?

Tharindu Lakshan
  • 3,995
  • 6
  • 24
  • 44
dosytres
  • 2,096
  • 3
  • 10
  • 21

20 Answers20

368

Change your code to accept a VoidCallback instead of Function for the onPressed.
By the way VoidCallback is just shorthand for void Function() so you could also define it as final void Function() onPressed;

Updated code:

class DrawerItem extends StatelessWidget {
    
      final String text;
      final VoidCallback onPressed;
    
      const DrawerItem({Key key, this.text, this.onPressed}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return FlatButton(
          child: Text(
            text,
            style: TextStyle(
              fontWeight: FontWeight.w600,
              fontSize: 18.0,
            ),
          ),
          onPressed: onPressed,
        );
      }
    }
Pieter van Loon
  • 5,318
  • 1
  • 6
  • 15
  • 2
    Is there any solution if I want a function with argument in it.For example Textfield function "onSubmitted", because it gives me the error as "The argument type 'void Function()?' can't be assigned to the parameter type 'void Function(String)?".Any solution for this error? – Hitesh Danidhariya Jun 28 '21 at 09:08
  • 2
    @HiteshDanidhariya yes you can simply add it in the brackets, i.e. `void Function(String myString)` – Pieter van Loon Jun 28 '21 at 10:46
129

Dart 2.12 (Null safety):

Instead of

final Function? onPressed; // Bad

use

final void Function()? onPressed; // Good
final VoidCallback? onPressed; // Good
CopsOnRoad
  • 237,138
  • 77
  • 654
  • 440
  • 2
    final Function()? onPressed; worked for me , thank you :) – Askani Jun 01 '21 at 12:04
  • Can you explain the logic behind it? Or point me some link about this? Thank you. – vietstone Aug 20 '21 at 23:22
  • 4
    @vietstone A `Function` can be anything, like `Function()`, `Function(int)`, etc, which is why with Dart null safety, you should explicitly tell what that `Function` is. – CopsOnRoad Aug 21 '21 at 13:24
  • @CopsOnRoad Thank you for your point. But I wonder that, as you say about Function() and Function(int), I think this is a kind of Polymorphism, not really Null Safety :D – vietstone Aug 21 '21 at 19:19
  • 2
    @vietstone Polymorphism is a different thing. `Function onPressed` can be invoked by `onPressed()`, `onPressed(1)`, `onPressed(1, true)` so, you may run into runtime error but `Function() onPressed` can only be invoked by `onPressed()`. This thing is not particular related to null safety but Dart 2.12. – CopsOnRoad Aug 21 '21 at 22:10
  • @CopsOnRoad yes, just curious about the name of this technique specifically – vietstone Aug 22 '21 at 02:58
  • short & effective answer... thanks :) – sina May 24 '22 at 17:34
17

Well that's because onPressed inside FlatButton is not a normal function its VoidCallBack Function. You can try something like this:

final VoidCallBack onPressed;

While, you are passing a normal function into a VoidCallBack

Follow the official doc here

enter image description here

Updated Code:

import 'package:flutter/material.dart';

void main() => runApp(new MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: HomeScreen(),
    );
  }
}

class HomeScreen extends StatelessWidget {
  _myFunction() => print("Being pressed!");

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
          children: [
            DrawerItem(
              text: "Hello Jee",
              onPressed: _myFunction,
            ),
          ],
        ),
      ),
    );
  }
}

class DrawerItem extends StatelessWidget {
  final String text;
  final Function onPressed;

  const DrawerItem({Key key, this.text, this.onPressed}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return FlatButton(
      child: Text(
        text,
        style: TextStyle(
          fontWeight: FontWeight.w600,
          fontSize: 18.0,
        ),
      ),
      onPressed: onPressed,
    );
  }
}
Hamza
  • 1,523
  • 15
  • 33
  • No, its not that the problem is still using final VoidCallBack onPressed; But thank you. – dosytres Oct 22 '20 at 14:26
  • Your code is working fine for me, what's your Flutter version? Or can you show me which `function` are you passing as parameter to `DrawerItem` – Hamza Oct 22 '20 at 14:34
  • my flutter version is 1.22.o, I know its old, but I have to use this one because i have an error with java and it wont work with an updated one. – dosytres Oct 22 '20 at 14:48
  • Actually your code is fine here, can you show me which type of `function` you are passing as a parameter? – Hamza Oct 22 '20 at 14:50
  • This is the full code, then iI want to be able to pass it to another file with the constructor – dosytres Oct 22 '20 at 15:02
  • It's not VoidCallBack. It's VoidCallback. The 'b' is in lowercase. – Reinier Garcia Apr 21 '23 at 03:24
8

Instead of

final Function? onPressed; 
Use
final Function()? onPressed; // add parenthesis in Function
Shivam Tiwari
  • 131
  • 1
  • 4
7

Put the parentheses () after the keyword Function when defining the function.

import 'package:flutter/material.dart';

class Answer extends StatelessWidget {
  final Function() onPressed; //parenthesis () on function
  final String name;
  const Answer(this.name, this.functionMessage, {Key? key}) : super(key: 
key);

  @override
  Widget build(BuildContext context) {
    return Container(
        margin: const EdgeInsets.only(top: 10),
        width: double.infinity,
        child: ElevatedButton(
           style: ElevatedButton.styleFrom(
           primary: Colors.black, // background
           onPrimary: Colors.white, // foreground
          ),
          onPressed: onPressed,
          child: Text(name),
        ));
  }
}
RileyManda
  • 2,536
  • 25
  • 30
Assem
  • 71
  • 1
  • 1
6

There are 2 possible solutions for this if you aware of data types in dart and null safety

1st:

add type VoidCallback?

class DrawerItem extends StatelessWidget {
      final String text;
      final VoidCallback? onPressed;
    
      const DrawerItem({Key key, this.text, this.onPressed}) : super(key: key); }

2nd:

if you are a beginner and don't know much about data type you can use dynamic and let dart compiler handled type for you.

class DrawerItem extends StatelessWidget {
          final String text;
          final dynamic onPressed;
    
      const DrawerItem({Key key, this.text, this.onPressed}) : super(key: key); }
Mashood .H
  • 926
  • 6
  • 16
3

If you still get this error "The parameter onPressed can't have a value of null because of its type, but the implicit default value is null." after modifying the onPressed function, just apply the null safety to fix the problem like this;

final VoidCallback? onPressed;

This works with Dart 2.x

Tharindu Lakshan
  • 3,995
  • 6
  • 24
  • 44
John
  • 313
  • 3
  • 8
3

use:

VoidCallback? _onPressed

instead of:

VoidCallback _onPressed

it's work for me!

2

You can use void Function instead of Function and you can specify you type of your function like this:

void Function(bool) onPressed;

 
ouflak
  • 2,458
  • 10
  • 44
  • 49
2
class TaskCheckBox extends StatelessWidget {
  final bool checkBoxState;
  **final void Function(bool? a)? onChecked**;

  const TaskCheckBox(
    this.checkBoxState,
    this.onChecked, {
    Key? key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Checkbox(
        activeColor: Colors.lightBlueAccent,
        value: checkBoxState,
        onChanged: **onChecked**);
  }
}
2

use

onPressed: () => delete(),

instead of

onPressed:delete,
1

If all above solution checked, then refer below code

class ManageMenu extends StatelessWidget {
  const ManageMenu(
      {Key? key,
      required this.faIcon,
      required this.text,
      required this.onTapFunction})
      : super(key: key);

  final FaIcon faIcon;
  final String text;
  final Function onTapFunction;

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () => onTapFunction,
      child: ListTile(
        leading: faIcon,
        title: Text(text),
      ),
    );
  }
}

You may wrote wrong syntax as onTap:onTapFunction instead of onTap: () => onTapFunction

MUHAMMAD SHAHID RAFI C P
  • 1,067
  • 1
  • 12
  • 25
1

Change your code to accept a VoidCallback instead of Function for the onPressed. By the way VoidCallback is just shorthand for void Function() so you could also define it as final void Function() onPressed;

Swaraj Kumar
  • 71
  • 1
  • 4
1

void Function(bool? a)? callback;

Check the screenshot of how void callback bool function work enter image description here

Musfiq Shanta
  • 1,298
  • 13
  • 9
0

2021: If you have a constructor accepting multiple parameters, you might want to use named arguments to avoid confusion:

Sample: Answer Button Widget

class AnswerButton extends StatelessWidget {
    
      late final Function()? submitAnswer;
    
      Answer({injectMethod}) {
        this.selectHandler = submitAnswer;
      }
    }

Main

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        home: Scaffold(
      appBar: AppBar(
        title: Text("App Title"),
      ),
      body: Column(
        children: [
          AnswerButton(injectMethod: _nextQuestion) /* <--- named argument */
        ],
      ),
    ));
  }
Mark Dionnie
  • 305
  • 4
  • 11
0

use:

dynamic onPressed;

or

onPressed; it will autodetect or set the parameter type as dynamic

instead of:

VoidCallback onPressed;

0

use this :

final void Function()? onTapping;

or

final voidCallback? onPressed; 
MD ALI
  • 13
  • 2
0

The Dart Sound null safety (sdk: '>=3.0.5 <4.0.0') will make you use:

final Function()? onPressed; //make use of parenthesis

instead of: final Function? onPressed; or: final void Function? onPressed;

Marcel Hofgesang
  • 951
  • 1
  • 15
  • 36
0

For any onTap, onPressed, onChange, etc. functions which returns void Function()?

Always use () => or () {} and then declare your function/functions...

For example:

@override
Widget build(BuildContext context) {
  return ElevatedButton(
    child: Text(text),
    onPressed: () => anyFunctionCall(), // ONLY SINGLE FUNCTION CAN BE CALLED
  );
}

OR

@override
Widget build(BuildContext context) {
  return ElevatedButton(
    child: Text(text),
    onPressed: () {
      firstFunctionCall(),
      secondFunctionCall(),
      // ... MULTIPLE FUNCTIONS CAN BE CALLED
    }
  );
}
littleironical
  • 1,593
  • 1
  • 11
  • 25
-1

if you are sending the parameter while calling the DrawerItem you should also add a parameter to Function like that final void Function(new par) onPressed;

yara.dev
  • 1
  • 1