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.

  1. 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,)
  1. 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,)
  1. 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)
  1. 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)
  1. 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

  1. Body It is simply the content within the curly braces.

enter image description here

  1. 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
  1. nullable ? OR required 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");
}

Tags:

Dart

Flutter