Flutter Notes
Flutter Summary
Dart
- Important concepts
-
As you learn about the Dart language, keep these facts and concepts in mind:
-
Everything you can place in a variable is an
Object
, and every object is an instance of a class. -
Although Dart is strongly typed, type annotations are optional because Dart can infer types. When you want to explicitly say that no type is expected, use the special type
dynamic
. -
Dart supports generic types, like
List<int>
(a list of integers) orList<dynamic>
(a list of objects of any type). -
Dart supports top-level functions (such as
main()
), as well as functions tied to a class or object (static and instance methods, respectively). You can also create functions within functions (nested or local functions). -
Similarly, Dart supports top-level variables, as well as variables tied to a class or object (static and instance variables). Instance variables are sometimes known as fields or properties.
-
Unlike Java, Dart doesn’t have the keywords
public
,protected
, andprivate
. If an identifier starts with an underscore (_
), it’s private to its library. For details, see Libraries and visibility. -
Identifiers can start with a letter or underscore (
_
), followed by any combination of those characters plus digits. -
Dart has both expressions (which have runtime values) and statements (which don’t). For example, the conditional expression condition ? expr1 : expr2 has a value of expr1 or expr2. Compare that to an if-else statement, which has no value. A statement often contains one or more expressions, but an expression can’t directly contain a statement.
-
Dart tools can report two kinds of problems: warnings and errors. Warnings are just indications that your code might not work, but they don’t prevent your program from executing. Errors can be either compile-time or run-time. A compile-time error prevents the code from executing at all; a run-time error results in an exception being raised while the code executes.
-
-
Built-in-types
-
The Dart language has special support for the following types:
- numbers
- strings
- booleans
- lists (also known as arrays)
- sets
- maps
- runes (for expressing Unicode characters in a string)
- symbols
- Numbers
- int
- double
- Strings
- Interpolate
'literal $name'
- Interpolate
'literal ${name.toUpperCase()}'
-
Concatenate
var s1 = 'String ' 'concatenation' " works even over line breaks."; var s1 = ''' You can create multi-line strings like this one. '''; var s2 = """This is also a multi-line string.""";
-
Raw string by prefixing with
r
var s = r'In a raw string, not even \n gets special treatment.';
- Interpolate
- Lists
-
In Dart, arrays are List objects, so most people just call them lists.
var list = [1, 2, 3];
-
For example, you can use the spread operator (
...
) to insert all the values of a list into another list:var list = [1, 2, 3]; var list2 = [0, ...list];
-
If the expression to the right of the spread operator might be null, you can avoid exceptions by using a null-aware spread operator (
?
):var list; var list2 = [0, ...?list]; assert(list2.length == 1);
-
Dart also offers collection
if
and collectionfor
, which you can use to build collections using conditionals (if) and repetition (for).var nav = [ 'Home', 'Furniture', 'Plants', if (promoActive) 'Outlet' ]; var listOfInts = [1, 2, 3]; var listOfStrings = [ '#0', for (var i in listOfInts) '#$i' ];
-
- Sets
-
A set in Dart is an unordered collection of unique items. Dart infers that halogens has the type
Set<String>
var halogens = {'fluorine', 'chlorine', 'bromine', 'iodine', 'astatine'};
-
To create an empty set, use
{}
preceded by a type argumentvar names = <String>{};
-
If you forget the type annotation on
{}
or the variable it’s assigned to, then Dart creates an object of typeMap<dynamic, dynamic>
. -
Add items to an existing set using the
add()
oraddAll()
methods:var elements = <String>{}; elements.add('fluorine'); elements.addAll(halogens);
-
Use .
length
to get the number of items in the set: -
To create a set that’s a compile-time constant, add
const
before the set literal:final constantSet = const { 'fluorine', 'chlorine', 'bromine', 'iodine', 'astatine', }; // constantSet.add('helium'); // This line will cause an error.
-
Sets support spread operators (
...
and...?
)
-
-
Maps
-
In general, a map is an object that associates keys and values.
var gifts = { // Key: Value 'first': 'partridge', 'second': 'turtledoves', 'fifth': 'golden rings' }; var nobleGases = { 2: 'helium', 10: 'neon', 18: 'argon', };
-
You can create the same objects using a
Map
constructor:var gifts = Map(); gifts['first'] = 'partridge'; gifts['second'] = 'turtledoves'; gifts['fifth'] = 'golden rings'; var nobleGases = Map(); nobleGases[2] = 'helium'; nobleGases[10] = 'neon'; nobleGases[18] = 'argon';
-
In Dart, the
new
keyword is optional -
Add
var gifts = {'first': 'partridge'}; gifts['fourth'] = 'calling birds'; // Add a key-value pair
-
Retrieve
var gifts = {'first': 'partridge'}; assert(gifts['first'] == 'partridge');
-
If you look for a key that isn’t in a map, you get a
null
in return:var gifts = {'first': 'partridge'}; assert(gifts['fifth'] == null);
-
Use .
length
to get the number of key-value pairs in the map:var gifts = {'first': 'partridge'}; gifts['fourth'] = 'calling birds'; assert(gifts.length == 2);
-
To create a map that’s a compile-time constant, add
const
before the map literal:final constantMap = const { 2: 'helium', 10: 'neon', 18: 'argon', }; // constantMap[2] = 'Helium'; // This line will cause an error.
-
-
-
Functions
-
Dart is a true object-oriented language, so even functions are objects and have a type,
Function
.bool isNoble(int atomicNumber) { return _nobleGases[atomicNumber] != null; }
-
For functions that contain just one expression, you can use a shorthand syntax: The
=>
expr syntax is a shorthand for{ return expr; }
. The=>
notation is sometimes referred to as arrow syntax.bool isNoble(int atomicNumber) => _nobleGases[atomicNumber] != null;
- Parameters
-
A function can have any number of required positional parameters. These can be followed either by named parameters or by optional positional parameters (but not both).
- Named parameters
-
Named parameters are optional unless they’re specifically marked as
required
. -
Calling with named parameters
enableFlags(bold: true, hidden: false);
-
Defining with named parameters
void enableFlags({bool bold, bool hidden}) {...}
-
Making required
const Scrollbar({Key key, @required Widget child})
-
- Optional parameters
-
Wrapping a set of function parameters in
[]
marks them as optional positional parameters:String say(String from, String msg, [String device]) { var result = '$from says $msg'; if (device != null) { result = '$result with a $device'; } return result; }
-
Wrapping a set of function parameters in
{}
marks them as optional non-positional parameters:
-
-
Default parameter values
void enableFlags({bool bold = false, bool hidden = false}) {...} String say(String from, String msg, [String device = 'carrier pigeon']) { var result = '$from says $msg with a $device'; return result; }
-
You can also pass lists or maps as default values.
void doStuff( {List<int> list = const [1, 2, 3], Map<String, String> gifts = const { 'first': 'paper', 'second': 'cotton', 'third': 'leather' }}) { print('list: $list'); print('gifts: $gifts'); }
-
-
- The main() function
-
Every app must have a top-level main() function, which serves as the entrypoint to the app. The main() function returns void and has an optional List
parameter for arguments. // Run the app like this: dart args.dart 1 test void main(List<String> arguments) { print(arguments); assert(arguments.length == 2); assert(int.parse(arguments[0]) == 1); assert(arguments[1] == 'test'); }
-
- Functions as first-class objects
-
You can pass a function as a parameter to another function. For example:
void printElement(int element) { print(element); } var list = [1, 2, 3]; // Pass printElement as a parameter. list.forEach(printElement);
-
You can also assign a function to a variable, such as:
var loudify = (msg) => '!!! ${msg.toUpperCase()} !!!'; assert(loudify('hello') == '!!! HELLO !!!');
-
- Anonymous functions
-
-
Operators
- Operator Meaning
as
Typecast (also used to specify library prefixes)is
True if the object has the specified typeis!
True if the object doesn’t have the specified type
- Cascade notation (..)
-
Cascades (
..
) allow you to make a sequence of operations on the same object. In addition to function calls, you can also access fields on that same object.querySelector('#confirm') // Get an object. ..text = 'Confirm' // Use its members. ..classes.add('important') ..onClick.listen((e) => window.alert('Confirmed!'));
-
- Operator Meaning
-
Control flow statements
-
Closures inside of Dart’s for loops capture the value of the index, avoiding a common pitfall found in JavaScript. For example, consider:
var callbacks = []; for (var i = 0; i < 2; i++) { callbacks.add(() => print(i)); } callbacks.forEach((c) => c()); //The output is 0 and then 1, as expected. //In contrast, the example would print 2 and then 2 in JavaScript.
- If the object that you are iterating over is an
Iterable
, you can use theforEach()
-
Iterable classes such as List and Set also support the for-in form of iteration:
var collection = [1, 2, 3]; for (var x in collection) { print(x); // 1 2 3 }
- Break and continue
-
break
to stop looping -
continue
to skip to next loop iterationfor (int i = 0; i < candidates.length; i++) { var candidate = candidates[i]; if (candidate.yearsExperience < 5) { continue; } candidate.interview(); } //or like this if using Iterable (eg for List or Set): candidates .where((c) => c.yearsExperience >= 5) .forEach((c) => c.interview());
-
- Switch and case
- Each non-empty
case
clause ends with abreak
statement, as a rule - Other valid ways to end a non-empty
case
clause are acontinue
,throw
, orreturn
statement. - Empty
case
clauses allows a form of fall-through. -
If you really want fall-through, you can use a
continue
statement and a label:var command = 'CLOSED'; switch (command) { case 'CLOSED': executeClosed(); continue nowClosed; // Continues executing at the nowClosed label. nowClosed: case 'NOW_CLOSED': // Runs for both CLOSED and NOW_CLOSED. executeNowClosed(); break; }
- Each non-empty
-
-
Exceptions
-
Classes
-
Generics
-
Libraries and visibility
-
Asynchrony support
- Handling Futures