Flutter 是什麼?用 Flutter 會省到時間嗎? @ GDG Devfest2020

Flutter 是什麼?用 Flutter 會省到時間嗎? @ GDG Devfest2020

Flutter 是什麼?可以吃嗎?
採用 Flutter 有什麼好處?一個新開的專案,我要用原生好還是用 Flutter 呢?
這次講題會快速帶過 Flutter 近期改版、關鍵概念、一些介紹常用的元件 與 經驗分享
希望給大家一個參考跟指引

#devfest2020
#gdgtaipei

8a6e58b272b266faf22d8a3b2927624f?s=128

Johnny Sung

October 17, 2020
Tweet

Transcript

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

  2. None
  3. •Flutter 是什麼? Dart 語⾔? •Flutter 畫⾯架構介紹 •Flutter ⼀些常⽤的元件 •⽤ Flutter

    開發有什麼要注意的? •我該⽤原⽣開發還是 Flutter 開發? •結論 ⼤綱
  4. 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)
  5. 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)
  6. 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
  7. •強型別,需事先宣告(類似 Java, C#) •物件導向 •底線開頭為 private •async await(類似 C#, JavaScript)

    •Future / Promise (Callback chaining)(類似 JavaScript) •Stream Dart 語⾔特性
  8. Flutter 畫⾯架構介紹

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

  10. 資料夾結構

  11. •StatefulWidget •StatelessWidget Flutter Widget

  12. 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 範例
  13. 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 範例
  14. StatelessWidget 範例 class MyStateLessWidget extends StatelessWidget { @override Widget build(BuildContext

    context) { // Implement widgets... return Container(); } }
  15. class MyHomePage extends StatefulWidget { MyHomePage({Key key, this.title}) : super(key:

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

    Text(widget.title), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ 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 範例
  17. StatefulWidget 範例

  18. None
  19. •Container •SizedBox •Row / Column •Text •Button •... 常⽤ Flutter

    Widget (呃...實在太多了)
  20. •強型別,需事先宣告(類似 Java, C#) •物件導向 •async await(類似 C#, JavaScript) •Future /

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

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

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

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

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

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

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

    Promise (Callback chaining)(類似 JavaScript) •Stream Material Components
  28. vs. ... 常⽤ Flutter Widget Material MaterialApp Scaffold CircularProgressIndicator MaterialButton

    AlertDialog BottomSheet Cupertino CupertinoApp CupertinoPageScaffold CupertinoActivityIndicator CupertinoButton ... CupertinoDialog CupertinoActionSheet
  29. 在 Flutter 的世界裡...

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

  31. Lifecycle

  32. 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
  33. (created) initState dispose (dirty) build (clean) didUpdateConfig setState (defunct) A

    State<T> 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<T> Lifecycle
  34. (created) initState dispose (dirty) build (clean) didUpdateConfig setState (defunct) class

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

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

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

  38. Future fetchData().then((result) { print(result); }).catchError((e) { print(e); }); Future<String> fetchData()

    async { return Future.delayed(Duration(seconds: 2), () { return 'data'; }); } 宣告 使⽤
  39. Future Future<String> fetchDataA() async { return Future.delayed(Duration(seconds: 2), () {

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

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

    fetchDataC(); }).then((dataC) { print(dataC); }).catchError((error) { print(error); }); Future<String> fetchDataA() async { return Future.delayed(Duration(seconds: 2), () { return 'dataA'; }); } Future<String> fetchDataB() async { return Future.delayed(Duration(seconds: 2), () { return 'dataB'; }); return 'dataB'; } Future<String> fetchDataC() async { return Future.delayed(Duration(seconds: 2), () { return 'dataC'; }); } Promise chain 寫法
  42. •Future 語法 •async / await 語法 同步?⾮同步?

  43. 同步?⾮同步? Future<String> 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); }); ⾮同步寫法 同步寫法
  44. Future<String> fetchData() async { return Future.delayed(Duration(seconds: 2), () { return

    'data'; }); } import 'package:http/http.dart' as http; Future<String> fetchData() async { final response = await http.get('https://example.com/'); return response.body; } Http package
  45. FutureBuilder

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

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

  48. FutureBuilder FutureBuilder<String>( future: fetchData(), builder: (BuildContext context, AsyncSnapshot<String> snapshot) {

    if (snapshot.hasData) { // Loaded complete! return Container(); } else if (snapshot.hasError) { // Loaded with error :( return Container(); } else { // Loading... return Container(); } }, );
  49. Stream

  50. Stream Stream<int> sampleOfStream() async* { yield 1; yield 2; yield

    3; yield 4; // Do something await Future.delayed(Duration(seconds: 3)); yield 5; }
  51. Stream Stream<MyState> sampleOfFetch() async* { yield MyLoadingState(); // Do fetch

    APIs MyResponse response = await fetchAPI(); yield MyLoadedState(); }
  52. Bloc

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

  55. class CounterCubit extends Cubit<int> { 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
  56. Cubit class MyCounter extends StatefulWidget { @override _MyCounterState createState() =>

    _MyCounterState(); } class _MyCounterState extends State<MyCounter> { CounterCubit _cubit = CounterCubit(); @override void initState() { super.initState(); _cubit = CounterCubit(); } @override void dispose() { _cubit.close(); super.dispose(); } @override Widget build(BuildContext context) { // ... } }
  57. Cubit @override Widget build(BuildContext context) { return Center( child: Column(

    children: [ BlocBuilder<CounterCubit, int>( cubit: _cubit, builder: (context, state) { return Text('Counter value: $state'); }), MaterialButton( child: Text('Increment'), onPressed: () { _cubit.increment(); }), MaterialButton( child: Text('Decrement'), onPressed: () { _cubit.decrement(); }), ], ), ); }
  58. 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 {}
  59. class MyDataBloc extends Bloc<MyBlocEvent, DataBlocState> { MyDataBloc() : super(DataBlocInitialState()); @override

    Stream<DataBlocState> 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
  60. class MyBlocWidget extends StatefulWidget { @override _MyBlocWidgetState createState() => _MyBlocWidgetState();

    } class _MyBlocWidgetState extends State<MyBlocWidget> { MyDataBloc _bloc; @override void initState() { super.initState(); _bloc = MyDataBloc(); } @override void dispose() { _bloc.close(); super.dispose(); } @override Widget build(BuildContext context) { // ... } } Bloc
  61. Bloc @override Widget build(BuildContext context) { return BlocBuilder<MyDataBloc, DataBlocState>( 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()); }); }); }
  62. 個⼈⼼得

  63. •enum ⽀援度不佳 •沒有 null safety(類似 Java, C#) •Method extensions ⽀援度不佳

    Dart 語⾔⼩缺點
  64. https://dart.dev/guides/language/language-tour#enumerated-types

  65. •enum ⽀援度不佳 •沒有 null safety(類似 Java, C#) •Method extensions ⽀援度不佳

    Dart 語⾔⼩缺點
  66. https://dart.dev/null-safety/understanding-null-safety

  67. Null safety

  68. 調整 pubspec.yaml 新增 analysis_options.yaml

  69. $ flutter clean $ flutter packages pub upgrade $ flutter

    pub run build_runner build https://stackoverflow.com/a/63328916/3663980 調整 pubspec.yaml 執⾏結果
  70. Int? Int 有問號 沒有問號 變數可以為空值 變數不可為空值

  71. var number: Int? = null var number2: Int = 1

    變數名稱 型態 值 變數名稱 型態 值 有問號 沒有問號 Kotlin
  72. int number2 = 1; 變數名稱 型態 值 變數名稱 型態 值

    有問號 沒有問號 int? number = null; Dart
  73. •enum ⽀援度不佳 •沒有 null safety(類似 Java, C#) •Method extensions ⽀援度不佳

    Dart 語⾔⼩缺點 Added in Dart 2.9
  74. Extension Methods extension NumberParsing on String { int parseInt() {

    return int.parse(this); } } var value = '200'.parseInt(); print(value);
  75. https://dart.dev/guides/language/extension-methods

  76. •enum ⽀援度不佳 •沒有 null safety(類似 Java, C#) •Method extensions ⽀援度不佳

    Dart 語⾔⼩缺點 Added in Dart 2.9 Added in Dart 2.7
  77. Flutter 套件 https://pub.dev/

  78. 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 為例)
  79. WebView

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

  81. ⽤ Flutter 會省到時間嗎?

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

  83. Q & A