Flutter Dart constructor
This is an example to supplement Günter Zöchbauer's explanation. It is the constructor of the Align widget.
class Align extends SingleChildRenderObjectWidget {
// constructor
const Align({
Key key, // named parameter
this.alignment = Alignment.center, // named parameter
this.widthFactor, // named parameter
this.heightFactor, // named parameter
Widget child // named parameter
}) : assert(alignment != null), // initializer list
assert(widthFactor == null || widthFactor >= 0.0), // initializer list
assert(heightFactor == null || heightFactor >= 0.0), // initializer list
super(key: key, child: child); // initializer list
// class variables
final AlignmentGeometry alignment;
final double widthFactor;
final double heightFactor;
More notes:
- parameters without the
this.
prefix are variables of the superclass. - parameters that do begin with
this.
are variables defined in the current class.
The constructor has two named parameters.
Named parameters are optional by default.@required
is an annotation recognized by the Dart analyzer and produces a warning if not passed when invoked at build time (it has no effect at run time).
:
starts the "initializer list", a comma sparated list of expressions executed before the constructors of the super classes and therefore also before the contructors body.
It is often used to check parameter values using assertions and to initialize final fields with calculated values.
A limitation is, that expressions can't read-access this.
(implicitely or explicitely) because the object initialization is not completed before the super constructors are executed.
The last element in the initializer is an implicit call to the default constructor of the super class if omitted, or the call to a specific constructor of the current class or the super class if given.
In the example in your question the key
parameter passed to the constructor is forwarded to the named parameter key
of the unnamed constructor of the super class.
Here is my detailed understanding on Flutter constructor
There will be only ONE constructor in a class, but could be multiple factory methods.
- Positional Parameters
These are the traditional parameters which are passed in same sequence as defined in constructor.
MyWidget(String param1, int param2) { debugPrint("Positional Optional $param1, $param2"); }
Calling
MyWidget('Param 1 Passed',2,)
- Named Parameters
Standard practice followed in flutter like where we quote param_name:value
. Below is example
MyWidget(String param1, {int? param2}) { debugPrint("Positional Optional $param1, $param2"); }
Calling
MyWidget('Param 1 Passed',param2: 2,)
- Optional Parameters
The optional parameters are wrapped in square brackets [ ]
MyWidget(String param1, [int? param2]) { debugPrint("Positional Optional, $param1, $param2"); }
Now as the param 2 is in between [ ]
, it makes the param 2 optional. so below are 2 ways to call it.
Way 1 : not passing param 2, the constructor will treat it as null if not passed.
MyWidget('Param 1 Passed',)
Way 2 : passing both params
MyWidget('Param 1 Passed',123)
- Required Parameters
When the parameter is to be passed mandatorily, we can use this by using keyword required
along with the { }
.
Rule : required
cannot be used with optional params i.e. [ ]
. Obviously, if it's a required param, it cannot be wrapped in optional [ ]
MyWidget(String param1, {required int param2}) { debugPrint("Positional Optional, $param1, $param2"); }
Calling
MyWidget('Param 1 Passed', param2: ,123)
- Colons
Colons are mainly used for the constructor parameter initialisation.
Rule : Initialisation cannot be done for params, it can only be for variables declared in class strTxt
in this case.
String strTxt; MyWidget(String param1, int param2) : strTxt = "Some Value" { debugPrint("Positional Optional, $param1, $param2, $strTxt"); }
Calling
MyWidget('Param 1 Passed', 123)
Result : Notice the "Some Value" in debugPrint
log which we set in :
Positional Optional, Param 1 Passed, 123, Some Value
- Body It is simply the content within the curly braces.
- Direct assignment via parameters
You might recall that in Android and some other languages, we pass the value in parameter and then equate it with class level variable. This is entirely shorten in Flutter by simply using this.class_level_var_name
. It simply assigns the passed value to that class level variable.
MyWidget(this.strTxt, int param2) { debugPrint("Positional Optional, $strTxt, $param2"); }
Calling
MyWidget('Param 1 Passed', 123)
Result
Positional Optional, Param 1 Passed, 123
- nullable
?
ORrequired
declaration
Declaring nullable is required ONLY when we make the parameter optional [ ]
or Named { }
, for parameter defined as normal, doesn't require the required
or nullable ?
Notice ?
in param2
MyWidget(this.strTxt, {int? param2}) { debugPrint("Positional Optional, $strTxt, $param2, $strTxt"); }
Notice required
MyWidget(this.strTxt, {required int param2}) { debugPrint("Positional Optional, $strTxt, $param2, $strTxt"); }