Make Function parameter optional in custom widget flutter - flutter

I try to create some custom widgets with some parameters in the constructor. This widget has some optional and required parameters.
how can make Function type parameter optional in my Widget.
class TextInputWithIcon extends StatefulWidget {
final String iconPath;
final String placeHolder;
final Function(bool) onFocusChange;
const TextInputWithIcon(
{Key key,
#required this.iconPath,
this.placeHolder = "",
this.onFocusChange})
: super(key: key);
#override
_TextInputWithIconState createState() => _TextInputWithIconState();
}
class _TextInputWithIconState extends State<TextInputWithIcon> {
#override
Widget build(BuildContext context) {
return MY_WIDGET;
}
}

Optional parameters can be either positional or named, but not both.
Named parameters are optional by default so you don't have to assign the default value.
If a parameter is optional but can’t be null, provide a default value.
With null safety
class TextInputWithIcon extends StatefulWidget {
final String iconPath;
final String placeHolder;
final Function(bool)? onFocusChange; // nullable and optional
const TextInputWithIcon(
{Key? key,
required this.iconPath, // non-nullable and required
this.placeHolder = "", // non-nullable but optional with a default value
this.onFocusChange, // nullable and optional
})
: super(key: key);
#override
_TextInputWithIconState createState() => _TextInputWithIconState();
}
Without null safety
const TextInputWithIcon(
{Key key,
#required this.iconPath,
this.placeHolder = "",
this.onFocusChange
})
: super(key: key);
Usage:
void _focusChanged(bool value) {
// using null-aware operator (for both with and without null safety)
onFocusChange?.call(value);
// or without null-aware operator
// with null safety
if(onFocusChange != null) {
onFocusChange!(value);
}
// without null safety
if(onFocusChange != null) {
onFocusChange(value);
}
}
Dart 2.17 update:
Although it often makes sense to place positional arguments first, named arguments can be placed anywhere in the argument list when it suits your API:
repeat(times: 2, () {
...
});
Have a look at Optional Parameters to understand better.
Edit: Thank you Jonah Williams to clarification.

You can use a default value that does nothing:
class TextInputWithIcon extends StatefulWidget {
final String iconPath;
final String placeHolder;
final Function(bool) onFocusChange;
const TextInputWithIcon(
{Key key,
#required this.iconPath,
this.placeHolder = "",
this.onFocusChange = _dummyOnFocusChange})
: assert(onFocusChange != null), super(key: key);
#override
_TextInputWithIconState createState() => _TextInputWithIconState();
static dynamic _dummyOnFocusChange(bool val) {}
}
I created a static named function instead of just a closure as a default value because closures are not const and currently default values need to be const.
I added the assert(...) to ensure that an error is shown when null is passed explicitly.

Another option if you don't like named parameters (like me :/) is:
function_name (argument1, [argument2]) {
// statements
}
arguments in brackets are optional.
source

Related

Widget is null inside initState

It's the first time a use Flutter (2.8.1) and I'having problems trying to undestrand what's going wrong.
I have a Stateful widget like this:
class SimpleWidget extends StatefulWidget {
final Type2 aValue;
const SimpleWidget({Key key, #required this.aValue}) : super(key: key);
#override
_SimpleWidgetState createState() => _SimpleWidgetState();
}
class _SimpleWidgetState extends State<SimpleWidget> {
Type1 color;
#override
void initState() {
super.initState();
color = widget.aValue; // <-- widget is null
}
...
}
that I call in this way:
List<Type1> something = await showDialog(
context: context,
builder: (context) {
print('currentElement.aValue: ${currentElement.aValue}'); // not null
return SimpleWidget(aValue: currentElement.aValue);
},
);
Why is widget.aValue == null in initState()? How can I solve it?
There are some error in your coding;
The first one is construction of SimpleWidget
const SimpleWidget({Key key, #required this.aValue}) : super(key: key);
when you call like SimpleWidget(aValue: currentElement.aValue); It will should error like key can not be null. You can use ? to make it nullable. Also, # should be remove, it is a syntax error
The correct one looks like
const SimpleWidget({Key? key, required this.aValue}) : super(key: key);
The second one is in SimpleWidgetState
You can change Type1 color; to late Type1 color;
Or make it nullable.
For more details, you can check flutter codelabs

How to Add and Use key in Custom widget constructors

I got notification warning (Not Error) about Use key in widget constructors. let say I have stateless class like this :
class TeaTile extends StatelessWidget {
final TheTea? tea;
const TeaTile({this.tea}); //the warning in hire!
#override
Widget build(BuildContext context) {
return Container();
}
}
the basic stateless format has a key like this :
class TeaTile extends StatelessWidget {
const TeaTile({ Key? key }) : super(key: key); //this one
#override
Widget build(BuildContext context) {
return Container();
}
}
I know how to disable the key rule use_key_in_widget_constructors: false. but I don't want to do it. so, how I add key in
final TheTea? tea;
const TeaTile({this.tea});
to solve the warning notification?
Update for Dart 2.17 using Super Initializers:
final TheTea? tea;
const TeaTile({ super.key, this.tea });
The super keyword in a constructor is a shortcut for the method below.
Older Dart versions:
final TheTea? tea;
const TeaTile({ Key? key, this.tea }) : super(key: key);
Basically a combination of both, you're still taking a named parameter key, that will pass it's value to the super constructor, and another named parameter tea that would set your final variable value.

Why is key required in constructor?

I have created class which extend StatefulWidget
class RegistrationPage extends StatefulWidget {
final String email;
const RegistrationPage({Key key, required this.email}) : super(key: key);
#override
_RegistrationPage createState() => _RegistrationPage();
}
The problem is android studio force me to put required before Key key. I googled some of examples how to pass values from screen to another screen and I have never seen that someone used required with Key.
I do it within:
Navigator.push(
context,
new MaterialPageRoute(
builder: (context) => RegistrationPage(email: email),
),
);
so just to pass email value. I need to make Key nullable to make it work.
Am I doing something wrong?
Because you're using null-safe Dart and key can't be null because it has a non-nullable type Key.
Solutions:
Use required
FooPage({required Key key});
Make key nullable.
FooPage({Key? key});
Remove key altogether.
FooPage();
I think your project is in null safety, with null safety a variable or object cannot be null execept if it is declared nullable.
Try adding a ? after Key:
class RegistrationPage extends StatefulWidget {
final String email;
const RegistrationPage({Key? key, required this.email}) : super(key: key);
#override
_RegistrationPage createState() => _RegistrationPage();
}
or you can simply delete the Key override:
class RegistrationPage extends StatefulWidget {
final String email;
const RegistrationPage({required this.email});
#override
_RegistrationPage createState() => _RegistrationPage();
}
I suggest you to read https://dart.dev/null-safety/understanding-null-safety
You're not doing anything wrong by making Key key nullable. The super constructors that you're passing the key to accept the nullable type.
So
const RegistrationPage({Key? key, required this.email}) : super(key: key);
is the norm as there is no reason to constrain the type by making it non-nullable and required.
If you have no need for keys with this widget, you can omit the super constructor and the key parameter completely.

Pass to Widget a Function that returns a future

I want to pass to my Widget a function that returns a future:
class CircularButtonWithIcon extends StatefulWidget {
CircularButtonWithIcon(
{Key key,
#required this.onPress,
this.activeStatus})
: super(key: key);
final Function activeStatus;
class _CircularButtonWithIconState extends State<CircularButtonWithIcon> {
bool active;
#override
void initState() {
super.initState();
widget.activeStatus.then(...);
}
However Dart's class Function has no way to specify that the function's return type.
Is it possible to do such thing?
You can add the return type front of the Function
i.e.
class CircularButtonWithIcon extends StatefulWidget {
Future<void> Function() activeStatus;
CircularButtonWithIcon({Key key, #required this.onPress, this.activeStatus,}) : super(key: key);
}

Error: type 'RequestCallBack' is not a subtype of type 'FirebaseUser'

I am making a simple app so that when the user presses the call-back button the callBack form pops-up, as I am implementing it using named routes so while pressing the call-back button I am getting this error: type 'RequestCallBack' is not a subtype of type 'FirebaseUser' while routing to callback form screen.
This is my routing file:
routes.dart
class RouteGenerator {
static Route<dynamic> generateRoute(RouteSettings settings) {
// Getting arguments passed in while calling Navigator.pushNamed
final argsFireBaseUser = settings.arguments;
final argsString = settings.arguments;
switch (settings.name) {
case '/request-call-back':
return MaterialPageRoute(
builder: (_) => RequestCallBack(user: argsFireBaseUser,
mobileNumber: argsString)
);
default:
return _errorRoute();
}
}
screen.dart
final String mobileNumber;
Screen({
Key key,
#required this.mobileNumber,
}) : assert(mobileNumber != null),
super(key: key);
onPressed:() {
Navigator.of(context).pushNamed('/request-call-back',
arguments: RequestCallBack(user: user,mobileNumber:
widget.mobileNumber,));
}
requestcallback.dart
class RequestCallBack extends StatefulWidget {
final String mobileNumber;
final FirebaseUser user;
RequestCallBack({
Key key,
#required this.user,
#required this.mobileNumber,
}) : assert(mobileNumber != null && user != null),
super(key: key);
#override
_RequestCallBackState createState() => _RequestCallBackState();
}
You don't have to pass whole widget over there. You have to pass those arguments as a list as following.
Navigator.of(context).pushNamed('/request-call-back',
arguments: [user,
widget.mobileNumber]);
In navigation route you also have to just pass list as following.
case '/request-call-back':
return MaterialPageRoute(
builder: (_) => RequestCallBack(data:settings.arguments) // changed
);
Now in stfull widget you can accept data as following.
class RequestCallBack extends StatefulWidget {
final List data;
RequestCallBack({
Key key,
#required this.data,
}) : assert(data != null),
super(key: key);
Now in State widget you can separate data.
final String mobileNumber = widget.data[0];
final FirebaseUser user = widget.data[1];
You are passing a RequestCallback as arguments of the pushNamed:
arguments: RequestCallBack(user: user,mobileNumber: widget.mobileNumber,));
But you are retrieving arguments as FirebaseUser:
final argsFireBaseUser = (RequestCallBack) settings.arguments;
You should first retrive arguments as a object:
final rc = settings.arguments;
And then get the user:
argsFireBaseUser = rc.user;