Flutter Fare Launch Event

The beginning of a wondrous journey

presented by Jack Frosch

Agenda

  • About me and this group
  • What you can look forward to
  • Your contribution to the group
  • A brief introduction to Dart
  • A brief introduction to Flutter

About Me

1st Career

About Me

2nd Career

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

What you can look forward to

  • Flutter and/or Dart Announcements
  • Widget-of-the-Week Video(s)
  • Dart Language Explorations
  • Flutter Explorations and Demos using the Featured Widgets

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!

Your contribution

  • Presenters wanted
  • Backup (co-organizer) needed
  • Logistics coordinator needed

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

// 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 - unordered, non-unique collection
  • Set - unordered, unique collection
  • Map - key/value dictionary of entries
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
import 'package:flutter_web/foundation.dart';

// 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);
}
//...

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!
  • Getting started
  • Creating a new app
  • A simple Flutter app using DartPad
  • A WIP expense app

Intro Video

Widget of the Week

Getting started

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

Simple App Demo

Flutter on DartPad Demo

Expense App Demo

Be warned: it's a WIP

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

Questions?