Flutter Fare Reboot
Rebooting our Flutter journey
presented by Jack Frosch
- I originally launched Flutter Fare in October 2019
-
In March 2020, we lost our meeting facility due to coronavirus concerns
-
Hoped we'd get back to normal in June
-
Online is our new normal for 2020
About me
In my first career,
I drove these...
In my second career,
I mostly drive these...
About Me
My other Meetup
1st Tuesday of the month
About The Group
- Independent Meetup (not Google sponsored)
- Our Meetup is for learning about Flutter and Dart
- Oriented toward Flutter and Dart newbies
- Previous programming knowledge is a prerequisite
- Syntax will be relatable to Java, TypeScript/JavaScript, Kotlin
Some of the topics we'll be covering
Dart
Flutter
- Types and Variables
- Object-oriented Dart
- Async Dart, including Streams
- Interesting Packages
- Much more!
- Widgets galore
- Layouts and Themes
- Navigation
- iOS L&F
- Interacting with servers
- Responsive, adaptive apps
- Much more!
2020 Calendar
Date | Topic |
---|---|
September 15th | Widget layouts, themes, fonts, and images |
October 20th | Menus, routing, dialogs, drawers, and more |
November 17th | State management & asynchronous programming |
December 15th | Flutter for Web and Desktop & adaptive apps |
Your contribution
- 2021 Presenters wanted
- Backup (co-organizer) needed
Agenda
- Why Flutter?
- Getting Started
- Dart Intro
- Flutter Intro
Why Flutter?
What is Flutter?
Mobile Application Development
One App, Two Code Bases
iOS
Why Not Code Native Apps?
iOS
-
The platform languages and approaches are different
-
Multiple teams likely needed
-
2X+ development and maintenance costs
-
Drift and deviation
and
Why Not Code Native Apps?
iOS
-
If U.S. is your only market, iPhone dominates
-
Worldwide, Android dominates
-
Customers will not change their phone to use your app
or
Why Not Code Native Apps?
One App, One Code Base
Ideally, we would write code once and have it work on both major mobile platforms
One App, One Code Base
- JavaScript
- Not same as React, but close
- Use same tool set for mobile & web apps
- Toolset compiles JS to native app UI widgets
- Non-UI code runs as JS
- App is packaged as a native app
- Some pre-built components, partly adaptive to OS
React Native
One App, One Code Base
- JavaScript
- Not compiled to native app code
- You just build a normal web application
- Web app is rendered in a web control
- App is packaged as a native app
- Loads of pre-built, fully adaptive components
Ionic
One App, One Code Base
- Uses the Dart language
- Compiles to native code
- Does not delegate to mobile OS widgets
- Pixel-perfect, fast rendering
- App packaged as native app
- Tons of prebuilt components, many with iOS L&F
Flutter
One App
Write Once
Write Twice
Java / Kotlin Android
Swift / Objective C iOS
React Native
Flutter
Ionic
Codebase
One App
Learn Once
Learn Twice
Java / Kotlin Android
Swift / Objective C iOS
Ionic
Flutter
React Native
Knowledgebase
One App
Must Write Your Own
Native Widgets
Included
Java / Kotlin Android
Swift / Objective C iOS
React Native
Widget Library
Ionic
Flutter
Getting Started
- Install Git (not covered)
- Install Flutter (also installs Dart)
- Install Editor
- Recommend Android Studio - Also does iOS
- Alternative Recommendation: VS Code
A (very) Brief Intro to Dart
- Important language concepts
- A simple program
- Flow control & Exceptions
- Built-in Types
- Lists, Sets, Maps
- Functions & Classes
Dart Language Concepts
- Everything is an object of some class type
- Strongly typed, but supports a dynamic type
- Generics supported (List<String>)
- Functions can be defined at top-level, in a class, or nested
- Variables can be defined at top-level or in a class
- Code organized into libraries we import to use
- Visibility of library items is public or private (indicated with _)
- Variable names start with letter or _, then can have digits
- Expressions have resulting value vs statements which don't
The DartPad
// main() is the entry point to a Dart application
// It takes an optional argument of type List<String>
void main() {
for (int i = 0; i < 5; i++) {
print('hello ${i + 1}');
}
}
// Outputs
hello 1
hello 2
hello 3
hello 4
hello 5
main()
class Dog {
String name;
String breed;
Dog(String name, String breed) {
this.name = name;
this.breed = breed;
}
String toString() {
return 'name: $name, breed: $breed';
}
}
void main() {
print(new Dog('Killer', 'Chihuahua'));
}
// outputs: name: Killer, breed: Chihuahua
constructors - positional parameters
class Dog {
String name;
String breed;
Dog(this.name, this.breed);
String toString() {
return 'name: $name, breed: $breed';
}
}
void main() {
print(new Dog('Killer', 'Chihuahua'));
print(Dog('Tiny', 'Great Dane')); // the new operator is optional
}
// outputs:
// name: Killer, breed: Chihuahua
// name: Tiny, breed: Great Dane
constructors - with field assignments
class Dog {
String name;
String breed;
Dog({this.name, this.breed});
String toString() {
return 'name: $name, breed: $breed';
}
}
void main() {
var dog = Dog(name: 'Tiny', breed: 'Great Dane');
print(dog); // the new operator is optional
}
// outputs:
// name: Tiny, breed: Great Dane
constructors - named parameters
// Top-level function.
int square(int a) { return a * a; }
class SquareUtil {
dynamic squareAnything(dynamic val) {
bool isNumber = val is num // this is how we can do runtime type checking
return isNumber ? val * val : val + val; // ternary operator supported
}
}
// This is the app entry point.
main() {
dynamic result;
var intVal = 9; // Declare and initialize a variable. Type inferred
result = square(intVal); // Call a function
print("Squaring int value ${intVal} yields ${result}");
var sqr = SquareUtil(); // instantiate an object of type SquareUtil
double doubleVal = 2.0;
result = sqr.squareAnything(doubleVal);
print("Squaring double value ${doubleVal} yields ${result}");
String sVal = 'frou';
result = sqr.squareAnything(sVal);
print("Squaring string value '${sVal}' yields ${result}");
}
A simple example
Flow Control
- if and else
- for loops
- while and do-while loops
- break and continue
- switch and case
- assert
Dart Types
- numbers
- strings
- booleans
- lists (also known as arrays)
- sets
- maps
- runes (for expressing Unicode characters in a string)
- symbols
Lists, Sets, Maps
- List - index ordered, non-unique collection
- Set - unordered, unique collection
- Map - key/value dictionary of entries
// Working with Lists
void main() {
var list = [ 3, 4, 5 ]; // type inferred as List<int>
var constList = const [ 6, 7, 8]; // const means fixed at compile-time
print("'Classic' C-style for loop");
for (int i = 0; i < list.length; i++) {
print("list[i] = ${list[i]}");
}
print("\nNewer-style for loop");
for (var value in list) {
print("value = $value");
}
list.add(6);
print("\nAdd 6 to the list: $list");
var newList = [ 2, ...list ];
print("\nNew list using spread operator: $newList");
var newListWithConditional = [
if (newList[0] == 2) 1,
...newList
];
print("\nNew list with conditional entry: $newListWithConditional");
var cubes = newListWithConditional.map((it) {
return it * it * it;
}).toList();
print("Cubes of newListWithConditional: $cubes");
// constList.add(9); // yields error
}
Working with Lists
// Working with Sets
void main() {
var items = { 'A', 'B', 'C'}; // type inferred as Set<String>
print("Items in set: $items");
print('\nAdd another String:');
items.add('D');
print("Items in set after add: $items");
print('\nAdd one or many:');
var newSet = <Object>{}; // element type explicitly Object
newSet.addAll(items);
newSet.add(5);
print("Items in newSet: $newSet");
print('\Remove an item:');
newSet.remove(5);
print("Items in newSet after remove: $newSet");
print('\nTry to add a duplicate:');
bool wasItAdded = newSet.add('B');
print("Item was added? $wasItAdded\nItems in newSet after trying to add duplicate: $newSet");
print('\nMake an immutable set:');
var immutableSet = const { 'X', 'Y', 'Z'};
print("Items in immutableSet: $immutableSet");
// immutableSet.add('Q');
}
Working with Sets
// Working with Maps
void main() {
var map = { 1: 'Chocolate', 2: 'Vanilla', 3: 'Strawberry' }; // type inferred as Map<int, String>
print("Created map = $map");
print('\nAccess individual entry:');
print("Value for key 2: ${map[2]}");
print('\nAccess missing key:');
print("Value for key 99: ${map[99]}");
print('\nAdd a new entry:');
map[4] = 'Moose Tracks';
print("Map after adding entry: $map");
print('\nOutput map using keys and values:');
map.forEach((key, value) {
print("key = $key, value = $value");
});
print('\nOutput map using map entries:');
map.entries.forEach((entry) {
print("key = ${entry.key}, value = ${entry.value}");
});
print('\nMake a new map out of the old:');
var newMap = Map<int, String>();
newMap.addAll(map);
newMap[5] = 'Mint Chocolate';
print("newMap = $newMap, length = ${newMap.length}");
var immutableMap = const { 'A123': 46, 'B456': 78, 'C789': 42 }; // type inferred as Map<String, int>
print("immutableMap = $immutableMap");
// immutableMap.remove('B456');
// final immutableReference = immutableMap;
// immutableReference = { 'A': 65, 'B': 66 };
}
Working with Maps
// Working with classes and functions
// main() is the entry point and a top level function
void main() {
print('Output Person using custom toString');
var person = Person(firstName: 'Fred', lastName: 'Flintstone');
print("Person person = $person");
print('\nOutput Dog:');
var dog = Dog(person, 'Buster');
print("Dog dog = $dog");
print("Dog using properties: name = ${dog.name}, breed = ${dog.breed}, owner = ${dog.owner}");
print('\nOutput Dog created with named constructor:');
var dog2 = Dog.poodle(person, 'Fluffy');
print("Dog using properties: name = ${dog2.name}, breed = ${dog2.breed}, owner = ${dog2.owner}");
print("Is dog a poodle? ${dog2.isPoodle()}");
print("Is dog a pitbull? ${dog2.isPitbull()}");
}
class Pet {
String name;
Pet(this.name);
}
class Dog extends Pet {
Person owner;
String breed;
Dog(Person owner, String name, [String breed]) : super(name) { // breed is optional
this.owner = owner;
this.breed = breed;
}
Dog.poodle(Person owner, String name) : super(name){
this.owner = owner;
this.breed = 'Poodle';
}
bool isPitbull() {
return this.breed == 'Pitbull';
}
bool isPoodle() => this.breed == 'Poodle';
}
class Person {
String firstName;
String middleName;
String lastName;
Person({this.firstName, this.middleName, this.lastName});
// instance method
String toString() {
return middleName == null ? "$firstName $lastName" : "$firstName $middleName $lastName";
}
}
Functions & Classes
//...
class Dog extends Pet {
Person owner;
String breed;
Dog(Person owner, String name, [String breed]) : super(name) { // breed is optional
this.owner = owner;
this.breed = breed;
}
Dog.poodle(Person owner, String name) : super(name){
this.owner = owner;
this.breed = 'Poodle';
}
bool isPitbull() {
return this.breed == 'Pitbull';
}
bool isPoodle() => this.breed == 'Poodle';
}
class Person {
String firstName;
String middleName;
String lastName;
Person({@required this.firstName, this.middleName, @required this.lastName});
// instance method
String toString() {
return middleName == null ? "${firstName} ${lastName}" : "${firstName} ${middleName} ${lastName}";
}
}
Functions & Classes
A (very) Brief Intro to Flutter
- Intro video
- In Flutter, everything is a widget!
- Demo - Creating a new app
- Flutter on DartPad Examples
- Flutter on the Web Examples
Intro Video
In Flutter, (almost) everything is a widget
Getting started
- Install Flutter: https://flutter.dev/docs/get-started/install
- Install IDE: https://flutter.dev/docs/get-started/editor
- Android Studio* (preferred)
- VS Code
- Create a new app (CLI or IDE)
A note about targeting iOS
- First - Android Studio works for both iOS and Android!
- When running an iOS simulator, you need iOS bits
- When deploying to App Store, deployment must be signed with a certificate provided by Apple
- You really need access to a Mac
- Alternative: CodeMagic
Creating a New App
via commandline
% cd ~/temp
% flutter create my_app
% cd my_app
% studio .
Flutter on DartPad Demos
Flutter for the web
Summary
- Dart is a very approachable language
- Everything in Flutter is a widget
- You'll need access to a Mac to do iOS testing and deployment*
- It's a great time to start learning Flutter!
Resources
-
Dart
-
Flutter
-
CodeMagic: https://codemagic.io
-
Me
-
Email: jackfrosch@flutterfare.com
-
Twitter: @jackfrosch, @flutterfare
-
LinkedIn: jackfrosch
-
Questions?
Flutter Fare Reboot
By Jack Frosch
Flutter Fare Reboot
A pandemic-friendly re-launch
- 1,359