Open SimonLab opened 4 years ago
The import
keyword allow us to use code from Dart built-in libraries (e.g core, math, async...), other people packages or from our own file code.
import 'dart:async`; // use dart: to import built-in libraries
import 'package:flutter/materials.dart'; // use package: to import packages via pub
import 'helpers/my_helpers.dart'; //user file path to reference other files in your project
The dart:core
library is automatically imported in every Dart programs.
You can create a prefix name for your imports with the as
keyword.
This can be useful to differentiate methods with the same name but from different package.
import 'dart:async' as async; // To use a method from the async pakcage you can now prefix it with async.
You can specify what to import from a package with the show
and hide
keywords:
import 'dart:async' show Future; // only import the Future class
import 'dart:async' hide Future; // import all from async except Future
You can use the deferred as
keyword to import code only when needed.
import 'lib/my_functions.dart' deferred as my_functions;
You will then need to call the loadLibrary
function to be able to access the method of the package.
Future func() async {
await my_functions.loadLibrary(); //load the library
my_functions.bonjour(); //call the bonjour method
}
See also the style guide when importing packages/files: https://dart.dev/guides/language/effective-dart/style#do-name-libraries-and-source-files-using-lowercase_with_underscores
references:
Similar to the main
function which is the entry point of the dart program, the runApp
function is the main entry point for your Flutter application.
runApp
takes a Widget as an argument which becomes the root widget of the application.
It's possible to call runApp
multiple times, however the last call will replace the previous widget tree and the last widget argument becomes the root widget:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp('hello'));
return runApp(MyApp('hello there!!'));
}
class MyApp extends StatelessWidget {
final String txt;
MyApp(this.txt);
@override
Widget build(BuildContext context) {
return Center( child: Text(txt, textDirection: TextDirection.ltr)
);
}
}
In this example the class MyApp
is a widget which takes a text to display on the screen as an argument.
We can see that the main
function calls MyApp
twice but only the latest widget will remain and display the hello there
text on the screen, the previous hello
is discarded.
runApp
doc: https://api.flutter.dev/flutter/widgets/runApp.html
A widget in Flutter is the configuration of some part of the UI. It describes how the UI element should be displayed on the screen.
A widget is immutable, so the instance variable of the widget class are final (can be assigned only one time) and the constructor of the class is using const
to force the creation of only one instance.
The immutable
annotation is also applied to the widget class:
@immutable
abstract class Widget extends DiagnosticableTree {
/// Initializes [key] for subclasses.
const Widget({ this.key });
Immutability is used with widgets to make it easier to determine which part of the UI needs to be updated.
It is easier to build
new widgets than to update them.
A stateless widget extends
the widget class:
abstract class StatelessWidget extends Widget {
const StatelessWidget({ Key key }) : super(key: key);
@override
StatelessElement createElement() => StatelessElement(this);
@protected
Widget build(BuildContext context);
}
The StatelessWidget
is an abstract class which define the build
interface (the body/logic of the method is left to the subclass to defined). In our example the MyApp
class is forced to implement the build
method and uses the override
annotation:
@override
Widget build(BuildContext context) {
return Center( child: Text(txt, textDirection: TextDirection.ltr)
);
}
The build method describes the UI part of the widget. It has a BuildContext as parameter which describe where the widget is placed in the widget tree. One common use case of the context is to access other parent widgets.
The build function is also responsible for creating any child widgets. For example if the Column is used in the build any widgets in the children properties will also be built. This process is repeated until there aren't anymore widget to build in the widget tree. This process is used to create widget composition. See also this short flutter video on BuildContext: https://www.youtube.com/watch?v=rIaaH87z1-g
// import the material package
// add the package in pubspec.yaml file and use the pub get command line
import 'package:flutter/material.dart';
// void main() => runApp(MyApp());
// this arrow syntax is the same as
void main() {
return runApp(MyApp()); //runApp returns void, so main has also void as returned type, https://api.flutter.dev/flutter/widgets/runApp.html
{
class MyApp extends StatelessWidget { // MyApp is a subclass of StatelesWidget
// the implementation of build is required on a stateless widget
// redefine the build function inherited from StatelessWidget
//the context describe where the MyApp widget is on the widget tree
@override
Widget build(BuildContext context) {
// the child is a Text Widget. MyApp widget is then composed of a child text widget
return Center( child: Text('hello', textDirection: TextDirection.ltr)
);
}
}
The small following example contains already multiple Flutter/Dart and OOP concepts. I'll try to explain them which hopefully will allow us to fully understand how this application works.