App Development With Flutter

Overview

  • What’s Flutter
  • Widgets
  • Render Trees (Widgets, Element, RenderObject)
  • Navigation & RouteAware
  • Communicate with Native
  • Networking
  • State Management

What’s Flutter

Flutter is Google’s mobile app SDK for crafting high-quality native interfaces on iOS and Android in record time. Flutter works with existing code, is used by developers and organizations around the world, and is free and open source.Flutter

Why use Flutter

  • Be highly productive
    • Develop for iOS and Android from a single codebase
    • Do more with less code, even on a single OS, with a modern, expressive language and a declarative approach
    • Prototype and iterate easily
      • Experiment by changing code and reloading as your app runs (with hot reload)
      • Fix crashes and continue debugging from where the app left off
  • Create beautiful, highly-customized user experiences
    • Benefit from a rich set of Material Design and Cupertino (iOS-flavor) widgets built using Flutter’s own framework
    • Realize custom, beautiful, brand-driven designs, without the limitations of OEM widget sets

Flutter architecture

Threading

flutter engine

  • Platform thread (main thread on android)
  • UI thread (Dart code)
  • GPU thread (Skia, graphics library)
  • I/O thread (I/O operation, Network)

Flutter Environment Setup

Entrance of Dart code

main.dart

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}
...

Widgets - layout & views in Flutter

  • Basic view widgets Text, Image, Button
  • Basic layout widgets Row, Column, Stack
  • Widget catalog

StatelessWidget & StatefulWidget

  • StatelessWidget (Widget without state)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
class Avatar extends StatelessWidget {
  final String url;

  Avatar({Key key, this.url}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      child: Image.asset(url)
    );
  }
}
  • StatefulWidget(Widget with state)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class CheckBox extends StatefulWidget {
  final bool checked;
  CheckBox({Key key, this.checked}) : super(key: key);

  _CheckBoxState createState() => _CheckBoxState();
}

class _CheckBoxState extends State<CheckBox> {
  bool _checked;

  @override
  void initState() {
    _checked = widget.checked;
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () {
        setState(() {
          _checked = !_checked;
        });
      },
      child: _checked ? Text('Checked') :Text('Unchecked'),
    );
  }
}

State lifecycle

Render Trees (Widgets, Element, RenderObject)



Navigator & PageRoute

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
MaterialApp(
  home: Screen1(),
  routes: <String, WidgetBuilder> {
    '/screen1': (BuildContext context) => Screen1(),
    '/screen2' : (BuildContext context) => Screen2(),
    '/screen3' : (BuildContext context) => Screen3(),
    '/screen4' : (BuildContext context) => Screen4()
  },
)

/** page stack
| screen4 |
| screen3 |
| screen2 |
| screen1 |
*/

Navigator.of(context).pushNamed('/screen2');
Navigator.of(context).pop()

Navigator.of(context).pushReplacementNamed('/screen4');
Navigator.popAndPushNamed(context, '/screen4');

Navigator.of(context).pushNamedAndRemoveUntil('/screen4', (Route<dynamic> route) => false);
Navigator.of(context).pushNamedAndRemoveUntil('/screen4', ModalRoute.withName('/screen1'));

Navigator.push(
  context,
   MaterialPageRoute(
     builder: (context) => Screen5(params: { })),
   ),
);

Navigator.of(context).push(new PageRouteBuilder(
  pageBuilder: (BuildContext context, _, __) {
    return Widget();
  },
  transitionDuration: const Duration(milliseconds: 250),
  transitionsBuilder: (_, Animation<double> animation, __, Widget child) {
    return SlideTransition(
      position: Tween<Offset>(
        begin: const Offset(0, 1),
        end: Offset.zero,
      ).animate(animation),
      child: child,
    );
  },
));

Communicate with Native

MethodChannel

Flutter code

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
const channel = MethodChannel('com.glowing.patient');
channel.invokeMethod('showToast', []);

channel.setMethodCallHandler(_handleMethod);

Future<dynamic> _handleMethod(MethodCall call) *async*{
  switch(call.method) {
    case 'showSnackBar':
      //TODO handle call from Native
      return Future.value(true);
  }
}

Native code

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
val channel = MethodChannel(flutterView, 'com.glowing.patient')
channel.invokeMethod("showSnackBar", null)
channel.setMethodCallHandler{
  call, result ->
  if(call.method == "showToast") {
 	  //TODO handle call from flutter
	  result.success(true)
  } else{
    result.notImplemented()
  }
}

Flutter plugin

Build your own plugin for Flutter

Networking

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
import 'package:http/http.dart'

Future<Post> fetchPost() async {
  final response =
      await http.get('https://jsonplaceholder.typicode.com/posts/1');

  if (response.statusCode == 200) {
    // If server returns an OK response, parse the JSON
    return Post.fromJson(json.decode(response.body));
  } else {
    // If that response was not OK, throw an error.
    throw Exception('Failed to load post');
  }
}

State Management

List of state management approaches

Resources

Licensed under CC BY-NC-SA 4.0
comments powered by Disqus
Built with Hugo
Theme Stack designed by Jimmy