learning a little about Flutter
experimenting some with Flutter
giving you just enough to start exploring it on your own
"Dart is a class-based, single-inheritance, pure object-oriented programming language. Dart is optionally typed and supports reified generics. The runtime type of every object is represented as an instance of class Type which can be obtained by calling the getter runtimeType declared in class Object, the root of the Dart class hierarchy.
"Dart programs may be statically checked. The static checker will report some violations of the type rules, but such violations do not abort compilation or preclude execution.
"Dart programs may be executed in one of two modes: production mode or checked mode. In production mode, static type annotations have absolutely no effect on execution with the exception of reflection and structural type tests. In checked mode, assignments are dynamically checked, and certain violations of the type system raise exceptions at run time."
developed at Google
developed because "Google cares about the Web"
specifically built for Google's own use
ECMA standard (ECMA-408): 4th Edition (December 2015)
see also https://dart.dev/guides/language/spec
targets multiple contexts
command-line applications
these run in the DartVM
front-end web development
these will typically transpile to Javascript
iOS/Android applications
makes use of Flutter (https://flutter.io)
https://www.dartlang.org/guides/language/language-tour
"a mobile app SDK for building high-performance, high-fidelity apps for iOS and Android, from a single codebase."
https://fltter.io/technical-overview/
mobile app SDK
optimized for 2D
ground-up GUI layer for mobile
written using Dart on top of some C++ code
modern React-style framework
test-friendly
composition:
small objects with narrow scopes of behavior, composed together
minimize inheritance/"IS-A"; maximize composition/"HAS-A"
functional:
UIs are built from functions that map state to UI primitives
this enables state to be built out of immutable data structures
reactive
declarative
https://flutter.dev => "Getting Started" => download and unpack the ZIP
run flutter doctor
to verify install, diagnose issues
run flutter update
to catch up to any recent changes
Flutter does rely on Android/iOS tools
Android Studio and/or XCode
Android Studio has Dart and Flutter plugins
you may want to use AS even on macOS/iOS
Flutter has VSCode plugins as well
simpler, more traditional hello world
app with centered "Hello, world" text
Hello, Flutter
import 'package:flutter/material.dart'; void main() { runApp( new Center( child: new Text( 'Hello, world!', textDirection: TextDirection.ltr, ), ), ); }
more complex than Hello World
button that tracks clicks
helps demonstrate more interesting aspects
Terminal
flutter create myapp
Optional: start emulator/simulator
flutter run
Choose from available "devices"
Android Studio
File|New Flutter Project
Optional: start emulator/simulator
Build
VSCode
View>Command Palette... 'Flutter:New Project'
select device in lower right corner of VSCode
Debug>Start Debugging
Flutter permits "hot reloading" of code
without losing intermediate state
example:
click the button a few times
change the text above the counter text
r
(from the debug terminal) hot reloads
notice counter has not reset to zero
pubspec.yaml
:
manifest file with dependencies and assets
you will probably edit this from time to time
pubspec.lock
: auto-generated/-managed
lib
: your source code
main.dart: entrypoint
test
: your test code
widget_test.dart: Scaffolded tests
android
: Android Studio project (Kotlin)
ios
: XCode project (Swift)
linux
: Linux/GTK project (C++)
macos
: macOS project (Swift)
web
: HTML project
windows
: Windows project (C++)
"Widgets describe what their view should look like given their current configuration and state. When a widget's state changes, the widget rebuilds its description, which the framework diffs against the previous description in order to determine the minimal changes needed in the underlying render tree to transition from one state to the next."
"Everything is a widget" and "Composition > Inheritance"
app starts with a root to the tree
Widget's job is to implement a build()
function
describes the widget in terms of other, lower-level widgets
eventually, RenderObjects do the actual painting/rendering
widgets are very narrowly-scoped
many widget types are entirely behavioral; no visible pixels
widgets can also contain other widgets
widgets can also provide behavior-only around other widgets
Simplest hello_world app
import 'package:flutter/material.dart'; void main() { runApp( new Center( child: new Text( 'Hello, world!', textDirection: TextDirection.ltr, ), ), ); }
Material: Android-esque
default look-and-feel assumption
import 'package:flutter/material.dart'
requires a "uses-material-design: true" in pubspec.yaml file
https://flutter.io/widgets/material
Cupertino: iOS-esque
import 'package:flutter/cupertino.dart'
https://flutter.io/widgets/cupertino
any sort of third-party widgets are possible/doable
Text: run of stylized text
also RichText for multiple different styles
Image: display a graphic
BMP, JPEG, PNG, GIF, animated GIF, ...
Icon: display an icon
icons are usually smaller images used for interaction
Row, Column: flexbox-inspired layout widgets
Container: create rectangular visual element ("box")
decorated with BoxDecoration (background, border, shadow)
AppBar: material design app (tool) bar
Scaffold: basic material design visual layout structure
appBar, body, bottomNavigationBar, floatingActionButton
RaisedButton: elevated pushbutton
onPressed invoked when button is pressed
FlatButton
FloatingActionButton
IconButton
PopupMenuButton
displays PopupMenuItems, CheckedPopupMenuItems, etc
DropdownButton
Checkbox
Radio
Switch
Slider
Date/Time pickers
your widgets are installed into the tree
those widgets (most often) manage other widgets
you build widget libraries!
StatelessWidget
these maintain no state internally
StatefulWidget
these manage state:
information that can be read synchronously when the widget is built
information that might change during the lifetime of the widget
these are immutable, and store state in State objects
takes a "functional-UI" approach
in other words, "UI = code(state)"
seen in React
greatly eases testing, to be sure
a subclass of StatefulWidget and a subclass of State
state class contains the widget’s mutable state and the widget’s build() method
when state changes, the state object calls setState()
Approach 1: widget manages its own state
Approach 2: parent manages the widget’s state
Approach 3: mix-and-match
is State user data? Manage it from the parent widget
is it aesthetic? Put it in the widget itself
when in doubt, manage it from the parent widget
"these two types of objects have different life cycles. Widgets are temporary objects, used to construct a presentation of the application in its current state. State objects on the other hand are persistent between calls to build(), allowing them to remember information."
a la button changing value in text
change notifications flow "up" the widget hierarchy by way of callbacks
current state flows "down" to the stateless widgets that do presentation
common parent that redirects this flow is the State
often called "pages" (a la Web pages)
similar to Android Activities
or iOS ViewControllers
a la Android Intents
or iOS Segues
uses Navigator class
creates an explicit stack-based structure
use push() to bring a new widget to the top
use pop() to remove a widget from the top ("go back")
The first page
<</home/runner/work/Slides/Slides/Content/Flutter/code/navigator_app/lib/main.dart NOT FOUND>>
for more-frequent use from different places in the app
routes array is set in MaterialApp constructor
then use pushNamed() instead of push() to navigate
Same app, using named routes
void main() { runApp(MaterialApp( title: 'Named Routes Demo', // Start the app with the "/" named route. In our case, the app will start // on the FirstScreen Widget initialRoute: '/', routes: { // When we navigate to the "/" route, build the FirstScreen Widget '/': (context) => FirstScreen(), // When we navigate to the "/second" route, build the SecondScreen Widget '/second': (context) => SecondScreen(), }, )); }
In FirstScreen/RaisedButton:
onPressed: () { // Navigate to the second screen using a named route Navigator.pushNamed(context, '/second'); },
In SecondScreen/RaisedButton:
onPressed: () { // Navigate to the second screen using a named route Navigator.pop(); },
pass data as additional arguments to pushNamed()
retrieve data using ModalRoute.of(), or
retrieve data inside an onGenerateRoute() provided to MaterialApp/CuptertinoApp constructor
Dart has a dart:convert library
JSON serializes to Map-of-String/dynamic pairs easily
deserialize using jsonDecode()
serialize using jsonEncode()
Inline serialization
// Given JSON of: // { // "name": "John Smith", // "email": "john@example.com" //} // ... in jsonString ... // Map<String, dynamic> user = jsonDecode(jsonString); print('Howdy, ${user['name']}!'); print('We sent the verification link to ${user['email']}.');
To/from model object classes
class User { final String name; final String email; User(this.name, this.email); User.fromJson(Map<String, dynamic> json) : name = json['name'], email = json['email']; Map<String, dynamic> toJson() => { 'name': name, 'email': email, }; }
https://pub.dev/packages/http
Future-based library for making HTTP requests
Simple one-shot HTTP req/resp
import 'package:http/http.dart' as http; var url = 'http://example.com/whatsit/create'; var response = await http.post(url, body: {'name': 'doodle', 'color': 'blue'}); print('Response status: ${response.statusCode}'); print('Response body: ${response.body}'); print(await http.read('http://example.com/foobar.txt'));
For frequent access to the same server...
var client = new http.Client(); try { var uriResponse = await client.post('http://example.com/whatsit/create', body: {'name': 'doodle', 'color': 'blue'}); print(await client.get(uriResponse.bodyFields['uri'])); } finally { client.close(); }
To customize HTTP session...
class UserAgentClient extends http.BaseClient { final String userAgent; final http.Client _inner; UserAgentClient(this.userAgent, this._inner); Future<StreamedResponse> send(BaseRequest request) { request.headers['user-agent'] = userAgent; return _inner.send(request); } }
Android Studio creates a "test" directory automatically
widget_test.dart offers up simple example of how to test widgets
each test file is its own "main()"
Example test script: widget_test.dart
// This is a basic Flutter widget test. // // To perform an interaction with a widget in your test, use the WidgetTester // utility that Flutter provides. For example, you can send tap and scroll // gestures. You can also use WidgetTester to find child widgets in the widget // tree, read text, and verify that the values of widget properties are correct. import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:basic/main.dart'; void main() { testWidgets('Counter increments smoke test', (WidgetTester tester) async { // Build our app and trigger a frame. await tester.pumpWidget(MyApp()); // Verify that our counter starts at 0. expect(find.text('0'), findsOneWidget); expect(find.text('1'), findsNothing); // Tap the '+' icon and trigger a frame. await tester.tap(find.byIcon(Icons.add)); await tester.pump(); // Verify that our counter has incremented. expect(find.text('0'), findsNothing); expect(find.text('1'), findsOneWidget); }); }
unit test
tests a single function, method, or class.
widget test
tests a single widget
in other UI frameworks referred to as component test
integration test
tests a complete app or a large part of an app.
if not already present...
add the test dev_dependency
add the test source directory
import 'package:test/test.dart';
import file of class under test
write void main()
then... write tests!
Tests take place in test calls
import 'package:test/test.dart'; import 'package:counter_app/counter.dart'; void main() { test('Counter value should be incremented', () { final counter = Counter(); counter.increment(); expect(counter.value, 1); }); }
Group tests together using group()
void main() { group('Counter', () { test('value should start at 0', () { expect(Counter().value, 0); }); test('value should be incremented', () { final counter = Counter(); counter.increment(); expect(counter.value, 1); }); test('value should be decremented', () { final counter = Counter(); counter.decrement(); expect(counter.value, -1); }); }); }
if not already present...
add the flutter_test dev_dependency
add the test source directory
import 'package:flutter_test/flutter_test.dart';
import file of class under test
write void main()
then... write tests!
testWidgets() method provides a WidgetTester (and is async)
await method calls on WidgetTester (like pumpWidget)
find widgets for testing using Finder functions
use expect() to match if widgets exist
void main() { testWidgets('MyWidget has a title and message', (WidgetTester tester) async { await tester.pumpWidget(MyWidget(title: 'T', message: 'M')); // Create our Finders final titleFinder = find.text('T'); final messageFinder = find.text('M'); expect(titleFinder, findsOneWidget); expect(messageFinder, findsOneWidget); }); }
Official
Website:
http://www.dartlang.org
Specification:
https://www.dartlang.org/docs/spec/latest/dart-language-specification.html
ECMA 408 (https://www.ecma-international.org/publications/standards/Ecma-408.htm)
Tutorials:
https://www.dartlang.org/docs/tutorials/
Official
Language Tour:
https://www.dartlang.org/guides/language/language-tour
Library Tour:
https://www.dartlang.org/guides/libraries/library-tour
Effective Dart
https://www.dartlang.org/guides/language/effective-dart
Futures Tutorial
https://www.dartlang.org/tutorials/language/futures
Streams Tutorial
https://www.dartlang.org/docs/tutorials/streams
Flutter docs
https://flutter.dev/docs
Flutter API reference
https://docs.flutter.io/
Widget catalog
https://flutter.dev/docs/development/ui/widgets
Technical Overview
https://flutter.dev/docs/resources/technical-overview
Flutter examples
in the examples/ directory of the SDK; build the flutter_gallery!
Flutter samples
https://github.com/flutter/samples
"Inside Flutter"
https://flutter.dev/docs/resources/inside-flutter
Who is this guy?
Architect, Engineering Manager/Leader, "force multiplier"
Principal -- Neward & Associates
http://www.newardassociates.com
Educative (http://educative.io) Author
Performance Management for Engineering Managers
Author
Professional F# 2.0 (w/Erickson, et al; Wrox, 2010)
Effective Enterprise Java (Addison-Wesley, 2004)
SSCLI Essentials (w/Stutz, et al; OReilly, 2003)
Server-Based Java Programming (Manning, 2000)