Slide 1

Slide 1 text

Flutter 是什麼? ⽤ Flutter 會省到時間嗎? Johnny Sung

Slide 2

Slide 2 text

No content

Slide 3

Slide 3 text

•Flutter 是什麼? Dart 語⾔? •Flutter 畫⾯架構介紹 •Flutter ⼀些常⽤的元件 •⽤ Flutter 開發有什麼要注意的? •我該⽤原⽣開發還是 Flutter 開發? •結論 ⼤綱

Slide 4

Slide 4 text

Flutter is an open-source UI software development kit created by Google. It is used to develop applications for Android, iOS, Linux, Mac, Windows, Google Fuchsia[4], and the web from a single codebase[5]. - Wikipedia https://en.wikipedia.org/wiki/Flutter_(software)

Slide 5

Slide 5 text

Dart is a client-optimized programming language for apps on multiple platforms. It is developed by Google and is used to build mobile, desktop, server, and web applications. Dart is an object-oriented, class-based, garbage- collected language with C-style syntax. Dart can compile to either native code or JavaScript. It supports interfaces, mixins, abstract classes, reified generics, and type inference. - Wikipedia https://en.wikipedia.org/wiki/Dart_(programming_language)

Slide 6

Slide 6 text

Skia Dart Text Foundation Animation Painting Rendering Widgets Material Gestures Engine (C++) Framework (Dart) Cupertino https://docs.google.com/presentation/d/1cw7A4HbvM_Abv320rVgPVGiUP2msVs7tfGbkgdrTy0I/edit#slide=id.g70d668005_2_22

Slide 7

Slide 7 text

•強型別,需事先宣告(類似 Java, C#) •物件導向 •底線開頭為 private •async await(類似 C#, JavaScript) •Future / Promise (Callback chaining)(類似 JavaScript) •Stream Dart 語⾔特性

Slide 8

Slide 8 text

Flutter 畫⾯架構介紹

Slide 9

Slide 9 text

iOS Plug-ins Android Plug-ins Flutter APIs (UI + Networking)

Slide 10

Slide 10 text

資料夾結構

Slide 11

Slide 11 text

•StatefulWidget •StatelessWidget Flutter Widget

Slide 12

Slide 12 text

import 'package:flutter/material.dart'; void main() => runApp(HelloWorldApp()); class HelloWorldApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Hello World App', home: Scaffold( appBar: AppBar( title: Text('Hello World App'), ), body: Center( child: Text('Hello World'), ), ), ); } } StatelessWidget 範例

Slide 13

Slide 13 text

import 'package:flutter/material.dart'; void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', home: MyHomePage(title: 'Flutter Demo Home Page'), ); } } StatefulWidget 範例

Slide 14

Slide 14 text

StatelessWidget 範例 class MyStateLessWidget extends StatelessWidget { @override Widget build(BuildContext context) { // Implement widgets... return Container(); } }

Slide 15

Slide 15 text

class MyHomePage extends StatefulWidget { MyHomePage({Key key, this.title}) : super(key: key); final String title; @override _MyHomePageState createState() => _MyHomePageState(); } class _MyHomePageState extends State { int _counter = 0; void _incrementCounter() { setState(() { _counter++; }); } @override Widget build(BuildContext context) { return Scaffold(...); } } StatefulWidget 範例

Slide 16

Slide 16 text

@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( 'You have pushed the button this many times:', ), Text( '$_counter', style: Theme.of(context).textTheme.headline4, ), ], ), ), floatingActionButton: FloatingActionButton( onPressed: _incrementCounter, tooltip: 'Increment', child: Icon(Icons.add), ), ); } StatefulWidget 範例

Slide 17

Slide 17 text

StatefulWidget 範例

Slide 18

Slide 18 text

No content

Slide 19

Slide 19 text

•Container •SizedBox •Row / Column •Text •Button •... 常⽤ Flutter Widget (呃...實在太多了)

Slide 20

Slide 20 text

•強型別,需事先宣告(類似 Java, C#) •物件導向 •async await(類似 C#, JavaScript) •Future / Promise (Callback chaining)(類似 JavaScript) •Stream Material Components

Slide 21

Slide 21 text

•強型別,需事先宣告(類似 Java, C#) •物件導向 •async await(類似 C#, JavaScript) •Future / Promise (Callback chaining)(類似 JavaScript) •Stream Material Components

Slide 22

Slide 22 text

•強型別,需事先宣告(類似 Java, C#) •物件導向 •async await(類似 C#, JavaScript) •Future / Promise (Callback chaining)(類似 JavaScript) •Stream Material Components

Slide 23

Slide 23 text

•強型別,需事先宣告(類似 Java, C#) •物件導向 •async await(類似 C#, JavaScript) •Future / Promise (Callback chaining)(類似 JavaScript) •Stream Material Components

Slide 24

Slide 24 text

•強型別,需事先宣告(類似 Java, C#) •物件導向 •async await(類似 C#, JavaScript) •Future / Promise (Callback chaining)(類似 JavaScript) •Stream Material Components

Slide 25

Slide 25 text

•強型別,需事先宣告(類似 Java, C#) •物件導向 •async await(類似 C#, JavaScript) •Future / Promise (Callback chaining)(類似 JavaScript) •Stream Material Components

Slide 26

Slide 26 text

•強型別,需事先宣告(類似 Java, C#) •物件導向 •async await(類似 C#, JavaScript) •Future / Promise (Callback chaining)(類似 JavaScript) •Stream Material Components

Slide 27

Slide 27 text

•強型別,需事先宣告(類似 Java, C#) •物件導向 •async await(類似 C#, JavaScript) •Future / Promise (Callback chaining)(類似 JavaScript) •Stream Material Components

Slide 28

Slide 28 text

vs. ... 常⽤ Flutter Widget Material MaterialApp Scaffold CircularProgressIndicator MaterialButton AlertDialog BottomSheet Cupertino CupertinoApp CupertinoPageScaffold CupertinoActivityIndicator CupertinoButton ... CupertinoDialog CupertinoActionSheet

Slide 29

Slide 29 text

在 Flutter 的世界裡...

Slide 30

Slide 30 text

萬物皆 Widget 在對應的狀態產⽣對應的畫⾯

Slide 31

Slide 31 text

Lifecycle

Slide 32

Slide 32 text

StatelessWidget constructor build A single StatelessWidget can build in many different BuildContexts StatefulWidget constructor createState A StatefulWidget creates a new State object for each BuildContext Widget Lifecycle https://docs.google.com/presentation/d/1cw7A4HbvM_Abv320rVgPVGiUP2msVs7tfGbkgdrTy0I/edit#slide=id.g70d668005_2_22

Slide 33

Slide 33 text

(created) initState dispose (dirty) build (clean) didUpdateConfig setState (defunct) A State object can rebuild if ... ... it receives a new configuration … it changes its internal state https://docs.google.com/presentation/d/1cw7A4HbvM_Abv320rVgPVGiUP2msVs7tfGbkgdrTy0I/edit#slide=id.g70d668005_2_22 State Lifecycle

Slide 34

Slide 34 text

(created) initState dispose (dirty) build (clean) didUpdateConfig setState (defunct) class MyWidget extends StatefulWidget { @override _MyWidgetState createState() => _MyWidgetState(); } class _MyWidgetState extends State { @override void initState() { super.initState(); } @override void dispose() { super.dispose(); } @override Widget build(BuildContext context) { return MaterialButton(onPressed: () { setState(() { // Edit value ... }); }); } }

Slide 35

Slide 35 text

Future

Slide 36

Slide 36 text

https://money.udn.com/money/story/5648/4705551

Slide 37

Slide 37 text

https://www.cna.com.tw/news/firstnews/202007090191.aspx

Slide 38

Slide 38 text

Future fetchData().then((result) { print(result); }).catchError((e) { print(e); }); Future fetchData() async { return Future.delayed(Duration(seconds: 2), () { return 'data'; }); } 宣告 使⽤

Slide 39

Slide 39 text

Future Future fetchDataA() async { return Future.delayed(Duration(seconds: 2), () { return 'dataA'; }); }

Slide 40

Slide 40 text

Future fetchDataA() async { return Future.delayed(Duration(seconds: 2), () { return 'dataA'; }); } Future fetchDataB() async { return Future.delayed(Duration(seconds: 2), () { return 'dataB'; }); return 'dataB'; } Future fetchDataC() async { return Future.delayed(Duration(seconds: 2), () { return 'dataC'; }); } Future 宣告

Slide 41

Slide 41 text

Future fetchDataA().then((dataA) { print(dataA); return fetchDataB(); }).then((dataB) { print(dataB); return fetchDataC(); }).then((dataC) { print(dataC); }).catchError((error) { print(error); }); Future fetchDataA() async { return Future.delayed(Duration(seconds: 2), () { return 'dataA'; }); } Future fetchDataB() async { return Future.delayed(Duration(seconds: 2), () { return 'dataB'; }); return 'dataB'; } Future fetchDataC() async { return Future.delayed(Duration(seconds: 2), () { return 'dataC'; }); } Promise chain 寫法

Slide 42

Slide 42 text

•Future 語法 •async / await 語法 同步?⾮同步?

Slide 43

Slide 43 text

同步?⾮同步? Future foo() async { String dataA = await fetchDataA(); String dataB = await fetchDataB(); String dataC = await fetchDataC(); return dataA + dataB + dataC; } Future.wait([fetchDataA(), fetchDataB(), fetchDataC()]).then((value) { print(value[0]); // dataA print(value[1]); // dataB print(value[2]); // dataC }).catchError((e) { print(e); }); ⾮同步寫法 同步寫法

Slide 44

Slide 44 text

Future fetchData() async { return Future.delayed(Duration(seconds: 2), () { return 'data'; }); } import 'package:http/http.dart' as http; Future fetchData() async { final response = await http.get('https://example.com/'); return response.body; } Http package

Slide 45

Slide 45 text

FutureBuilder

Slide 46

Slide 46 text

萬物皆 Widget 在對應的狀態產⽣對應的畫⾯

Slide 47

Slide 47 text

•在對應的 狀態 產⽣畫⾯ •狀態 •初始狀態 •載⼊中 •載⼊完成 •有錯誤 FutureBuilder

Slide 48

Slide 48 text

FutureBuilder FutureBuilder( future: fetchData(), builder: (BuildContext context, AsyncSnapshot snapshot) { if (snapshot.hasData) { // Loaded complete! return Container(); } else if (snapshot.hasError) { // Loaded with error :( return Container(); } else { // Loading... return Container(); } }, );

Slide 49

Slide 49 text

Stream

Slide 50

Slide 50 text

Stream Stream sampleOfStream() async* { yield 1; yield 2; yield 3; yield 4; // Do something await Future.delayed(Duration(seconds: 3)); yield 5; }

Slide 51

Slide 51 text

Stream Stream sampleOfFetch() async* { yield MyLoadingState(); // Do fetch APIs MyResponse response = await fetchAPI(); yield MyLoadedState(); }

Slide 52

Slide 52 text

Bloc

Slide 53

Slide 53 text

No content

Slide 54

Slide 54 text

•製作定義 Event •根據對應的 Event 或 State 產⽣資料 Bloc

Slide 55

Slide 55 text

class CounterCubit extends Cubit { CounterCubit() : super(0); /// Add 1 to the current state. void increment() => emit(state + 1); /// Subtract 1 from the current state. void decrement() => emit(state - 1); } Cubit

Slide 56

Slide 56 text

Cubit class MyCounter extends StatefulWidget { @override _MyCounterState createState() => _MyCounterState(); } class _MyCounterState extends State { CounterCubit _cubit = CounterCubit(); @override void initState() { super.initState(); _cubit = CounterCubit(); } @override void dispose() { _cubit.close(); super.dispose(); } @override Widget build(BuildContext context) { // ... } }

Slide 57

Slide 57 text

Cubit @override Widget build(BuildContext context) { return Center( child: Column( children: [ BlocBuilder( cubit: _cubit, builder: (context, state) { return Text('Counter value: $state'); }), MaterialButton( child: Text('Increment'), onPressed: () { _cubit.increment(); }), MaterialButton( child: Text('Decrement'), onPressed: () { _cubit.decrement(); }), ], ), ); }

Slide 58

Slide 58 text

abstract class DataBlocState {} class DataBlocInitialState extends DataBlocState {} class DataBlocLoadingState extends DataBlocState {} class DataBlocLoadedState extends DataBlocState { final String result; DataBlocLoadedState({this.result}); } class DataBlocErrorState extends DataBlocState { final Error error; DataBlocErrorState(this.error); } 初始的狀態 載⼊中的狀態 載⼊完成的狀態 錯誤的狀態 abstract class MyBlocEvent {} class MyBlocLoadEvent extends MyBlocEvent {}

Slide 59

Slide 59 text

class MyDataBloc extends Bloc { MyDataBloc() : super(DataBlocInitialState()); @override Stream mapEventToState(MyBlocEvent event) async* { if (state is DataBlocLoadingState) { return; } try { if (event is MyBlocLoadEvent) { yield DataBlocLoadingState(); String result = await fetchData(); yield DataBlocLoadedState(result: result); } } catch (e) { yield DataBlocErrorState(e); } } } Bloc

Slide 60

Slide 60 text

class MyBlocWidget extends StatefulWidget { @override _MyBlocWidgetState createState() => _MyBlocWidgetState(); } class _MyBlocWidgetState extends State { MyDataBloc _bloc; @override void initState() { super.initState(); _bloc = MyDataBloc(); } @override void dispose() { _bloc.close(); super.dispose(); } @override Widget build(BuildContext context) { // ... } } Bloc

Slide 61

Slide 61 text

Bloc @override Widget build(BuildContext context) { return BlocBuilder( cubit: _bloc, builder: (context, state) { if (state is DataBlocLoadingState) { return CircularProgressIndicator(); } else if (state is DataBlocErrorState) { return Text('Error: ' + state.error.toString()); } else if (state is DataBlocLoadedState) { return Text("Complete! " + state.result); } return MaterialButton(onPressed: () { _bloc.add(MyBlocLoadEvent()); }); }); }

Slide 62

Slide 62 text

個⼈⼼得

Slide 63

Slide 63 text

•enum ⽀援度不佳 •沒有 null safety(類似 Java, C#) •Method extensions ⽀援度不佳 Dart 語⾔⼩缺點

Slide 64

Slide 64 text

https://dart.dev/guides/language/language-tour#enumerated-types

Slide 65

Slide 65 text

•enum ⽀援度不佳 •沒有 null safety(類似 Java, C#) •Method extensions ⽀援度不佳 Dart 語⾔⼩缺點

Slide 66

Slide 66 text

https://dart.dev/null-safety/understanding-null-safety

Slide 67

Slide 67 text

Null safety

Slide 68

Slide 68 text

調整 pubspec.yaml 新增 analysis_options.yaml

Slide 69

Slide 69 text

$ flutter clean $ flutter packages pub upgrade $ flutter pub run build_runner build https://stackoverflow.com/a/63328916/3663980 調整 pubspec.yaml 執⾏結果

Slide 70

Slide 70 text

Int? Int 有問號 沒有問號 變數可以為空值 變數不可為空值

Slide 71

Slide 71 text

var number: Int? = null var number2: Int = 1 變數名稱 型態 值 變數名稱 型態 值 有問號 沒有問號 Kotlin

Slide 72

Slide 72 text

int number2 = 1; 變數名稱 型態 值 變數名稱 型態 值 有問號 沒有問號 int? number = null; Dart

Slide 73

Slide 73 text

•enum ⽀援度不佳 •沒有 null safety(類似 Java, C#) •Method extensions ⽀援度不佳 Dart 語⾔⼩缺點 Added in Dart 2.9

Slide 74

Slide 74 text

Extension Methods extension NumberParsing on String { int parseInt() { return int.parse(this); } } var value = '200'.parseInt(); print(value);

Slide 75

Slide 75 text

https://dart.dev/guides/language/extension-methods

Slide 76

Slide 76 text

•enum ⽀援度不佳 •沒有 null safety(類似 Java, C#) •Method extensions ⽀援度不佳 Dart 語⾔⼩缺點 Added in Dart 2.9 Added in Dart 2.7

Slide 77

Slide 77 text

Flutter 套件 https://pub.dev/

Slide 78

Slide 78 text

environment: sdk: ">=2.11.0-9.0 <3.0.0" dependencies: flutter: sdk: flutter fluttertoast: ^7.1.1 http: ^0.12.0+2 bloc: ^6.0.3 flutter_bloc: ^6.0.5 cached_network_image: ^2.3.2+1 shared_preferences: ^0.5.1+2 firebase_core: ^0.5.0 firebase_analytics: ^6.0.1 firebase_admob: ^0.10.0+1 flutter_svg: ^0.19.0 url_launcher: ^5.4.1 url_launcher_macos: 0.0.1+8 provider: ^4.1.3 flutter_slidable: ^0.5.7 uuid: ^2.2.2 cupertino_icons: ^1.0.0 Flutter 套件 (列出其⼀專案的 pubspec.yaml 為例)

Slide 79

Slide 79 text

WebView

Slide 80

Slide 80 text

•Flutter 官網 • https://flutter.dev/ •Flutter 中⽂翻譯 • https://flutter.cn/docs Flutter 學習資源

Slide 81

Slide 81 text

⽤ Flutter 會省到時間嗎?

Slide 82

Slide 82 text

熟悉你的⼯具,熟能⽣巧 就會省到時間

Slide 83

Slide 83 text

Q & A