Flutter Fare Reboot
Rebooting our Flutter journey
presented by Jack Frosch
![](https://s3.amazonaws.com/media-p.slid.es/uploads/362103/images/6595352/flutter-logo.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/362103/images/6595352/flutter-logo.png)
- 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...
![](https://s3.amazonaws.com/media-p.slid.es/uploads/362103/images/2417624/38th_Tactical_Reconnaissance_Squadron_-_McDonnell_Douglas_RF-4C-41-MC_Phantom_-_69-0350.jpg)
In my second career,
I mostly drive these...
![](https://s3.amazonaws.com/media-p.slid.es/uploads/362103/images/6666713/macbook-pro.jpg)
About Me
My other Meetup
![](https://s3.amazonaws.com/media-p.slid.es/uploads/362103/images/5287984/St_Louis_Serverless.jpg)
1st Tuesday of the month
About The Group
![](https://s3.amazonaws.com/media-p.slid.es/uploads/362103/images/6595352/flutter-logo.png)
- 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
![](https://s3.amazonaws.com/media-p.slid.es/uploads/362103/images/6595352/flutter-logo.png)
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
![](https://s3.amazonaws.com/media-p.slid.es/uploads/362103/images/6595352/flutter-logo.png)
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
![](https://s3.amazonaws.com/media-p.slid.es/uploads/362103/images/6595352/flutter-logo.png)
- 2021 Presenters wanted
- Backup (co-organizer) needed
Agenda
![](https://s3.amazonaws.com/media-p.slid.es/uploads/362103/images/6595352/flutter-logo.png)
- Why Flutter?
- Getting Started
- Dart Intro
- Flutter Intro
![](https://s3.amazonaws.com/media-p.slid.es/uploads/362103/images/7644624/Flutter_By_Google.png)
Why Flutter?
What is Flutter?
Mobile Application Development
One App, Two Code Bases
![](https://s3.amazonaws.com/media-p.slid.es/uploads/362103/images/7644670/android.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/362103/images/7644664/Swift.png)
iOS
Why Not Code Native Apps?
![](https://s3.amazonaws.com/media-p.slid.es/uploads/362103/images/7644670/android.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/362103/images/7644664/Swift.png)
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?
![](https://s3.amazonaws.com/media-p.slid.es/uploads/362103/images/7644670/android.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/362103/images/7644664/Swift.png)
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?
![](https://s3.amazonaws.com/media-p.slid.es/uploads/362103/images/7644718/Mobile_Marketshare.png)
One App, One Code Base
![](https://s3.amazonaws.com/media-p.slid.es/uploads/362103/images/7644659/React_Native_Flutter_Ionic.png)
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
![](https://s3.amazonaws.com/media-p.slid.es/uploads/362103/images/7644659/React_Native_Flutter_Ionic.png)
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
![](https://s3.amazonaws.com/media-p.slid.es/uploads/362103/images/7644659/React_Native_Flutter_Ionic.png)
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
![](https://s3.amazonaws.com/media-p.slid.es/uploads/362103/images/7644659/React_Native_Flutter_Ionic.png)
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
![](https://s3.amazonaws.com/media-p.slid.es/uploads/362103/images/6595352/flutter-logo.png)
- Install Git (not covered)
- Install Flutter (also installs Dart)
- Install Editor
- Recommend Android Studio - Also does iOS
- Alternative Recommendation: VS Code
![](https://s3.amazonaws.com/media-p.slid.es/uploads/362103/images/6595352/flutter-logo.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/362103/images/7647001/Install_Flutter.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/362103/images/6595352/flutter-logo.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/362103/images/7647152/Android_Studio_Install.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/362103/images/6595352/flutter-logo.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/362103/images/7647163/VS_Code_Install.png)
A (very) Brief Intro to Dart
![](https://s3.amazonaws.com/media-p.slid.es/uploads/362103/images/6595352/flutter-logo.png)
- Important language concepts
- A simple program
- Flow control & Exceptions
- Built-in Types
- Lists, Sets, Maps
- Functions & Classes
Dart Language Concepts
![](https://s3.amazonaws.com/media-p.slid.es/uploads/362103/images/6595352/flutter-logo.png)
- 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
![](https://s3.amazonaws.com/media-p.slid.es/uploads/362103/images/6595352/flutter-logo.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/362103/images/6658041/DartPad.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/362103/images/6595352/flutter-logo.png)
// 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()
![](https://s3.amazonaws.com/media-p.slid.es/uploads/362103/images/6595352/flutter-logo.png)
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
![](https://s3.amazonaws.com/media-p.slid.es/uploads/362103/images/6595352/flutter-logo.png)
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
![](https://s3.amazonaws.com/media-p.slid.es/uploads/362103/images/6595352/flutter-logo.png)
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
![](https://s3.amazonaws.com/media-p.slid.es/uploads/362103/images/6595352/flutter-logo.png)
// 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
![](https://s3.amazonaws.com/media-p.slid.es/uploads/362103/images/6595352/flutter-logo.png)
- if and else
- for loops
- while and do-while loops
- break and continue
- switch and case
- assert
Dart Types
![](https://s3.amazonaws.com/media-p.slid.es/uploads/362103/images/6595352/flutter-logo.png)
- numbers
- strings
- booleans
- lists (also known as arrays)
- sets
- maps
- runes (for expressing Unicode characters in a string)
- symbols
Lists, Sets, Maps
![](https://s3.amazonaws.com/media-p.slid.es/uploads/362103/images/6595352/flutter-logo.png)
- List - index ordered, non-unique collection
- Set - unordered, unique collection
- Map - key/value dictionary of entries
![](https://s3.amazonaws.com/media-p.slid.es/uploads/362103/images/6595352/flutter-logo.png)
// 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
![](https://s3.amazonaws.com/media-p.slid.es/uploads/362103/images/6595352/flutter-logo.png)
// 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
![](https://s3.amazonaws.com/media-p.slid.es/uploads/362103/images/6595352/flutter-logo.png)
// 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
![](https://s3.amazonaws.com/media-p.slid.es/uploads/362103/images/6595352/flutter-logo.png)
// 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
![](https://s3.amazonaws.com/media-p.slid.es/uploads/362103/images/6595352/flutter-logo.png)
//...
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
![](https://s3.amazonaws.com/media-p.slid.es/uploads/362103/images/6595352/flutter-logo.png)
- Intro video
- In Flutter, everything is a widget!
- Demo - Creating a new app
- Flutter on DartPad Examples
- Flutter on the Web Examples
![](https://s3.amazonaws.com/media-p.slid.es/uploads/362103/images/6595352/flutter-logo.png)
Intro Video
![](https://s3.amazonaws.com/media-p.slid.es/uploads/362103/images/7647526/Flutter_Widget_Catalog.png)
In Flutter, (almost) everything is a widget
Getting started
![](https://s3.amazonaws.com/media-p.slid.es/uploads/362103/images/6595352/flutter-logo.png)
- 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
![](https://s3.amazonaws.com/media-p.slid.es/uploads/362103/images/6595352/flutter-logo.png)
- 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
![](https://s3.amazonaws.com/media-p.slid.es/uploads/362103/images/6595352/flutter-logo.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/362103/images/6658000/CodeMagic.jpg)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/362103/images/6595352/flutter-logo.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/362103/images/6657900/Flutter_Commands.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/362103/images/6595352/flutter-logo.png)
Creating a New App
via commandline
% cd ~/temp
% flutter create my_app
% cd my_app
% studio .
![](https://s3.amazonaws.com/media-p.slid.es/uploads/362103/images/6595352/flutter-logo.png)
Flutter on DartPad Demos
![](https://s3.amazonaws.com/media-p.slid.es/uploads/362103/images/6595352/flutter-logo.png)
Flutter for the web
![](https://s3.amazonaws.com/media-p.slid.es/uploads/362103/images/6595352/flutter-logo.png)
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?
![](https://s3.amazonaws.com/media-p.slid.es/uploads/362103/images/1791761/spongebob_confused.gif)
Flutter Fare Reboot
By Jack Frosch
Flutter Fare Reboot
A pandemic-friendly re-launch
- 1,419