INTRODUCTION TO
FLUTTER
DART PROGRAMMING LANGUAGE
The Dart language
is type safe - Snippet
var staticType = "String";
it uses static type checking to ensure that a variable's value always matches the
variable's static type
Type Inference
dynamic dynamicType = "String";
dynamicType = 10;
Usage of dynamic type combined with runtime checks
Dart has built-in sound null safety.
The following code sample showcases several Dart language features, including
libraries, async calls, nullable and non-nullable types, arrow syntax, generators,
streams, and getters. To learn more about the language, check out the
Dart language tour. 2
DART PROGRAMMING LANGUAGE
The Dart language
has type Inference
is type safe
it uses static type checking to ensure that a variable's value always matches the
variable's static type
Usage of dynamic type combined with runtime checks
Dart has built-in sound null safety.
3
DART PROGRAMMING LANGUAGE –
HELLO WORLD
void main() {
print('Hello, World!');
}
4
DART PROGRAMMING LANGUAGE -
VAR
Dart has built-in sound null safety.
var flybyObjects = ['Jupiter', 'Saturn', 'Uranus',
'Neptune'];
var image = {
'tags': ['saturn'],
'url': '//path/to/saturn.jpg’};
void main() {
/// Types declaration
var name = 'Voyager I';
var year = 1977;
var antennaDiameter = 3.7;
}
5
DART PROGRAMMING LANGUAGE –
EXPLICIT/NULLABLE
is type safe
/// Explicit not nullable declaration and assignment
int declaredType;
declaredType = 5;
/// Explicit nullable declaration and check
int? nullableVariable;
if(nullableVariable == null)
print("Nullable");
6
DART PROGRAMMING LANGUAGE -
STATIC/DYNAMIC
it uses static type checking to ensure that a
variable's value always matches the variable's
static type
/// Static type assignment
var staticType = "String";
staticType = 10.toString();
/// Dynamic type assignment
dynamic dynamicType = "String";
dynamicType = 10;
7
DART PROGRAMMING LANGUAGE – FINAL
and CONST
Final is calculated only one time at runtime and
then cannot be changed.
Const is calculated at COMPILE TIME and cannot be
assigned or changed at runtime.
/// final and const variables
final finalVar =
DateTime.now();
const constVar = 3.14;
8
DART PROGRAMMING LANGUAGE – STRING
FORMAT
/// String formatting
print('String formatting:');
print(name + " " + year.toString() + " " +
image['url'].toString());
print("$name $year ${image['url']}"); // Best practice for
DART
9
DART PROGRAMMING LANGUAGE – IF
STATEMENT
/// If Statement
print("If statement:");
if (year >= 2001) {
print('21st century');
} else if (year >=
1901) {
print('20th century');
}
10
DART PROGRAMMING LANGUAGE – SWITCH
CASE
/// Switch statement
print("Switch
statement:");
switch(year) {
case(1977):
print("Correct Year");
case(1978):
print("Incorrect Year");
}
11
DART PROGRAMMING LANGUAGE –
FOREACH
/// Foreach object
for (final object in
flybyObjects) {
print(object);
}
12
DART PROGRAMMING LANGUAGE – FOR
CYCLE
/// For Cycle and increment operators
for (int month = 1; month <= 3; month++) {
print(month);
}
print("---");
for (int month = 1; month <= 3; ) {
print(++month); // Count and print
}
13
DART PROGRAMMING LANGUAGE – WHILE
LOOP
/// While loop
while (year < 1985) {
year += 1;
}
14
DART PROGRAMMING LANGUAGE – WHILE
LOOP
/// Inline conditions
var a = year ?? 0; // Not Null
print(a);
var b = year > 1982 ? 1 : -
1; // Condition
print(b);
15
DART PROGRAMMING LANGUAGE – IMPORT
and =>
import 'DartLanguageTypesAndFlow.dart’;
void main () {
/// '=>' operator
flybyObjects.where((name) =>
name.contains('tu')).forEach(print);
}
16
DART PROGRAMMING LANGUAGE –
CLASSES
/// class
class Spacecraft {
String name;
DateTime? launchDate;
/// Read-only non-final property
int? get launchYear => launchDate?.year;
/// Constructor, with syntactic sugar for assignment to
members.
Spacecraft(this.name, this.launchDate) {
/// Initialization code goes here.
}
}
17
DART PROGRAMMING LANGUAGE –
METHODS
@override
String toString() {
return describe();
}
/// Named constructor that forwards to the default one.
Spacecraft.unlaunched(String name) : this(name, null);
/// Method.
String describe() {
String tempString = ('Spacecraft: $name');
/// Type promotion doesn't work on getters.
var launchDate = this.launchDate;
if (launchDate != null) {
int years = DateTime.now().difference(launchDate).inDays ~/ 365;
return '$tempString Launched: $launchYear ($years years ago)';
} else {
return '$tempString Unlaunched';
}
} 18
DART PROGRAMMING LANGUAGE –
OBJECTS and LISTs
/// objects
var Apollo = Spacecraft("Apollo 1", null);
print(Apollo.toString());
var Apollo2 = Spacecraft("Apollo 2", DateTime.now());
print(Apollo2.toString());
/// Lists
/// ---
var SpacecraftList = {Apollo, Apollo2, Spacecraft("Moon Lander",
DateTime(1978))};
SpacecraftList.forEach((spacecraft){print(spacecraft.toString());});
19
DART PROGRAMMING LANGUAGE – ENUM
/// Simple Enum
enum PlanetType { terrestrial, ice, gas }
/// Enum that enumerates the different planets in our solar system
/// and some of their properties.
enum Planet {
mercury(planetType: PlanetType.terrestrial, moons: 0, hasRings: false),
venus(planetType: PlanetType.terrestrial, moons: 0, hasRings: false),
// ···
uranus(planetType: PlanetType.ice, moons: 27, hasRings: true),
neptune(planetType: PlanetType.ice, moons: 14, hasRings: true);
/// A constant generating constructor
const Planet(
{required this.planetType, required this.moons, required
this.hasRings});
/// All instance variables are final
final PlanetType planetType;
final int moons;
final bool hasRings;
/// Enhanced enums support getters and other methods
bool get isGiant =>
planetType == PlanetType.gas || planetType == PlanetType.ice;
}
20
DART PROGRAMMING LANGUAGE – ENUM
/// Simple Enum
enum PlanetType { terrestrial, ice, gas }
/// Enum that enumerates the different planets in our solar system
/// and some of their properties.
enum Planet {
mercury(planetType: PlanetType.terrestrial, moons: 0, hasRings: false),
venus(planetType: PlanetType.terrestrial, moons: 0, hasRings: false),
// ···
uranus(planetType: PlanetType.ice, moons: 27, hasRings: true),
neptune(planetType: PlanetType.ice, moons: 14, hasRings: true);
/// A constant generating constructor
const Planet(
{required this.planetType, required this.moons, required
this.hasRings});
/// All instance variables are final
final PlanetType planetType;
final int moons;
final bool hasRings;
/// Enhanced enums support getters and other methods
bool get isGiant =>
planetType == PlanetType.gas || planetType == PlanetType.ice;
}
21
FLUTTER ARCHITECTURE
Dart App
•Composes widgets into the desired UI.
•Implements business logic.
•Owned by app developer.
Framework (source code)
•Provides higher-level API to build high-quality apps (for example, widgets,
hit-testing, gesture detection, accessibility, text input).
•Composites the app's widget tree into a scene.
Engine (source code)
•Responsible for rasterizing composited scenes.
•Provides low-level implementation of Flutter's core APIs (for example,
graphics, text layout, Dart runtime).
•Exposes its functionality to the framework using the dart:ui API.
•Integrates with a specific platform using the Engine's Embedder API.
Embedder (source code)
•Coordinates with the underlying operating system for access to services like
rendering surfaces, accessibility, and input.
•Manages the event loop.
•Exposes platform-specific API to integrate the Embedder into apps.
Runner
•Composes the pieces exposed by the platform-specific API of the Embedder
into an app package runnable on the target platform.
•Part of app template generated by flutter create, owned by app developer.
22
FLUTTER HELLO WORLD!
import
'package:flutter/material.dart';
void main() {
runApp(
const Center(
child: Text(
'Hello, world!',
textDirection: TextDirection.ltr,
),
),
);
}
23
WIDGETs
24
WIDGET LIFECYCLE
25
WIDGET LIFECYCLE
createState
When Flutter is instructed to build
a StatefulWidget, it immediately calls createState()
Init State
Called when this object is inserted into the tree. didChangeDependencies
When inserting the render tree when invoked, this Called when a dependency of this [State] object
function is called only once in the life cycle. Here changes.
you can do some initialization, such as initializationdidUpdateWidget
State variables. Called whenever the widget configuration changes.
setState deactivate
The setState() method is called often from the Called when this object is removed from the tree.
Flutter framework itself and the developer. Before dispose, we will call this function.
dispose
Called when this object is removed from the tree
permanently.
didChangeAppLifecycleState
Called when the system puts the app in the
background or returns the app to the foreground.
26
https://stackoverflow.com/questions/41479255/life-cycle-
WIDGETS
https://docs.flutter.dev/ui/widgets
Text:
The Text widget lets you create a run of styled text within your application.
Row, Column:
These flex widgets let you create flexible layouts in both the horizontal (Row) and vertical
(Column) directions. The design of these objects is based on the web's flexbox layout model.
Stack:
Instead of being linearly oriented (either horizontally or vertically), a Stack widget lets you
place widgets on top of each other in paint order. You can then use the Positioned widget on
children of a Stack to position them relative to the top, right, bottom, or left edge of the
stack. Stacks are based on the web's absolute positioning layout model.
Container:
The Container widget lets you create a rectangular visual element. A container can be
decorated with a BoxDecoration, such as a background, a border, or a shadow.
A Container can also have margins, padding, and constraints applied to its size. In addition,
a Container can be transformed in three-dimensional space using a matrix.
27
LET’S TRY TO USE ALL THE
ELEMENTS!
28
DART – THROW and CATCH
EXCEPTIONs
throw FormatException('Expected at least 1
section’);
try {
isThisThingWorking();
}
on Exception {
print(“This thing is not working!”);
}
29
DART – ASYNCHRONOUS
PROGRAMMING (basic)
Asynchronous programming
A
B A C
B Synchronous programming ?
U U
C 1 2
S
U U
1 2
S
30
DART – ASYNCHRONOUS
PROGRAMMING (basic)
Future<void> fetchUserOrder() {
// Imagine that this function is fetching user info from another
service or database.
return Future.delayed(const Duration(seconds: 2), () =>
print('Large Latte'));
}
void main() {
fetchUserOrder();
print('Fetching user order...');
}
31
DART – ASYNCHRONOUS
PROGRAMMING (basic)
Future<String> createOrderMessage() async {
var order = await fetchUserOrder();
return 'Your order is: $order’;
}
Future<String> fetchUserOrder() =>
Future.delayed( const Duration(seconds: 2), () => 'Large
Latte', );
Future<void> main() async {
print('Fetching user order...’);
print(await createOrderMessage());
}
32
DART – ASYNCHRONOUS
PROGRAMMING (basic)
// NOT WRITE LIKE THIS!!!
String createOrderMessage() {
var order = fetchUserOrder();
return 'Your order is: $order';
}
Future<String> fetchUserOrder() =>
// Imagine that this function is more complex
and slow.
Future.delayed(
const Duration(seconds: 2),
() => 'Large Latte',
);
void main() {
print(createOrderMessage());
}
33
DART – ASYNCHRONOUS
PROGRAMMING (basic)
import 'dart:math';
Future<String> createOrderMessage()
async {
var order = await fetchUserOrder(); Future<void> getSugar() =>
return 'Your order is: $order'; // Imagine that this function is
}
// more complex and slow.
Future<String> fetchUserOrder() => Future.delayed(Duration(seconds:
// Imagine that this function is Random().nextInt(5)),
// more complex and slow. () => print('Sugar taken'));
Future.delayed(
Duration(seconds: Future<void> main() async {
Random().nextInt(5)), print('Fetching user order...');
() => 'Large Latte',); getSugar();
print(await createOrderMessage());
}
34
FLUTTER – THE MATERIAL CLASS
class ElabFTWAppRead extends StatelessWidget {
const ElabFTWAppRead({super.key});
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return const Material(
child: MainPage(title: 'elabFTW API Read Main
Page'),
);
}
}
35
FLUTTER – UI DESIGN and CREATION
36
FLUTTER – UI DESIGN and CREATION
1 -:
Widget build(BuildContext context) { 2 3
return Container(
color: const Color(0xFF0BBD9D), 1
width: 360,
height: 54,
padding: const EdgeInsets.only(left: 5, right: 5, top: 5,
bottom: 5),
child: Row(textDirection: TextDirection.ltr, children: [ … ] ), );
} 2 -: 3 -:
Expanded( const Expanded(
child: Align( child: Align(
alignment: Alignment.centerLeft, alignment:
child: Text( Alignment.centerRight,
title, child: Icon(
textDirection: TextDirection.ltr, textDirection:
textAlign: TextAlign.center, TextDirection.ltr,
style: const TextStyle( color: Colors.white,
color: Colors.white, Icons.more_horiz,
fontFamily: 'Roboto', ),
fontSize: 14, ),
), ),
), ]));
), }
), } 37
FLUTTER – THE MATERIAL APP CLASS
MaterialApp(
theme: ThemeData(
brightness: Brightness.dark,
primaryColor: Colors.blueGrey ),
home: Scaffold(
appBar: AppBar(
title: const Text('MaterialApp
Theme’), ),
),
)
38
FLUTTER – APPBAR CLASS
39
FLUTTER – HTTP PACKAGE
40
FLUTTER – HTTP PACKAGE
main.dart
pubspec.yaml
41
FLUTTER – HTTP PACKAGE
args: chrome/webbrowsers --web-browser-flag "--disable-web-security"
42
FLUTTER – API REQUESTs
late Future<String> _responseStr;
final String API_Auth_Token = $TOKEN;
Future<List<Map<int, String>>> fetchExperiments() async {
print("get!");
final response = await http.get(
Uri.parse(
"https://prp-electronic-lab.areasciencepark.it/api/v2/experiments"),
headers: {"Authorization": API_Auth_Token});
print(response.statusCode.toString());
if (response.statusCode == 200) {
List experimentsList = json.decode(response.body);
experimentsList.forEach(
(element) => print("${element['id']} : ${element['title']}"));
return List<Map<int,
String>>.from(experimentsList.map((element) =>
<int, String>{element['id']: element['title']} as Map<int,
String>));
late Future<List<Map<int, String>>> futureExperiment
} else {
// If the server did not return a 200 OK response,
@override
// then throw an exception.
void initState() {
throw Exception('Failed to find experiments');
super.initState();
}
futureExperiments = fetchExperiments();
}
}
43
FLUTTER – FUTURE BUILDER
child: FutureBuilder<List<Map<int, String>>>(
future: futureExperiments,
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Center(child: CircularProgressIndicator());
} else {
return Container(
child: SizedBox(
width: 200,
height: 500,
child: ListView.builder(
itemCount: snapshot.data!.length,
scrollDirection: Axis.vertical,
itemBuilder: (BuildContext context, int
index) {
return GestureDetector(
child: Text('${snapshot.data!
[index].keys}'),
onTap: () => _showExperiment(
snapshot.data![index].values.first),
);
})));
}
}),
), 44