First Flutter Application
Learning Objectives
- You know what Flutter is and know how to create a simple application with Flutter.
- You know how variables and functions are defined in Dart.
Flutter is a framework for building multi-platform applications that work on a range of devices. Applications built with Flutter use the Dart programming language, and rely on a range of utilities from Flutter and third-party libraries.
Building applications with Flutter is based on the concept of widgets. Widgets are the building blocks of a Flutter application, and are used to define most if not all aspects of an application. These aspects include: (1) the layout and styles of the user interface, (2) the components shown in the interface, and (3) the interactive functionality of the interface.
In terms of object-oriented programming, widgets are objects that are used to define the structure and behavior of the application.
Structure of a Flutter application
Composing a Flutter application is done by creating a hierarchy of widgets. The hierarchy is built from the root widget, which is typically a MaterialApp widget, and continues with other widgets that define the application’s layout and functionality. As an example, a basic Flutter application with an application bar and centered text would be implemented as follows.
The application imports the material
package from Flutter, which provides functionality for building the application. The classes used above are as follows:
- MaterialApp is a class that provides convenience settings for the application.
- Scaffold is a class that defines basic Material Design layout structure and settings to the application.
- AppBar is a class that is used to define the application bar.
- Text is a class that is used to define the text shown in the application.
- Center is a class that is used to center its contents.
The application is started by calling the runApp function, which takes the root widget of the application as an argument, and renders the application, showing it to the user.
The concept of the widget hierarchy is similar to the Document Object Model used in building web applications.
Main function and variables
The above Flutter example relies on a number of features from the Dart programming language, starting from having a main
function that is the entry point of the application, which is called when a Dart program is executed. A classic “Hello world!” program that many introductory programming courses start with would be written in Dart as follows.
The Flutter example also creates a handful of objects out of the classes provided by Flutter, such as MaterialApp
, Scaffold
, AppBar
, Text
, and Center
. If we would wish to use variables to hold the values, the whole program could be explicitly written out as follows.
Although the above example explicitly states the variable types, Dart allows for type inference, which means that the types of variables can be inferred from the values assigned to them. To rely on type inference, variables can be declared using var
. The following example demonstrates the same program but with type inference.
The var
declaration states that the type of the variable should be inferred from the value assigned to it. As Dart enforces type safety, once the variable type has been inferred from the value assigned to it, or once the type has been explicitly set, the variable type cannot change. As an example, the following code would result in a compilation error, as the type of centeredText
has been inferred as Center
and thus it cannot be assigned a value of type Text
.
While variables that have been declared with var
and explicit type declarations can be reassigned, variables declared with final
cannot be reassigned. The following example demonstrates the same program (without the error) with variables declared as final
.
Variables and functions in Dart should be named using lowerCamelCase
. For additional details, see Effective Dart: Style.
Functions
As mentioned earlier, the entry function to a Dart program is the main
function. In addition to the main
function, we can define our own functions to structure our code. As an example, in the following program, the declaration of the Flutter application has been extracted to a separate function called myApp
, which returns the MaterialApp
object.
Functions in Dart have a return type, function name, optional parameters, and a function body. If the return type is not specified, Dart sets the return type as void
.
In the following example, we define a function called average
that has double
as the return type, two parameters (both int
), and a function body that calculates the average of the two parameters. The function is called in the main
function, where the value returned from the function is printed.
Similarly, the following function takes two strings (first name and last name) as parameters, and returns a James Bond -like greeting as a string. The example also demonstrates string interpolation, where the values of the parameters are inserted into the string using the $
character.
In both of the above examples, when defining the functions, we have explicitly stated the return type and the types of the parameters. Although not mandatory, this is a good practice, as it makes the code easier to read and understand, and it also helps the compiler to catch errors.
Explicitly specify function return type and the types of the parameters.
When reading Dart code, it is common to see the arrow syntax in function declarations. The arrow syntax is used to define a function that executes the expression followed by the arrow. As an example, the following program would print “Hello world!”.
Similarly, the following declares the average function using the arrow syntax.
The arrow syntax is often used when defining short functions that consist of a single expression. The arrow syntax can be used with functions that have a return type, but it cannot be used with functions that have a function body. As an example, the following function would result in a compilation error, as the arrow syntax cannot be used with functions that have a function body.
Dart features also anonymous functions. Anonymous functions are functions that do not have a name. They are often used as arguments to other functions, or when a function is needed only once. We’ll see examples of anonymous functions later.