Upgrade to Pro — share decks privately, control downloads, hide ads and more …

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

Johnny Sung
October 17, 2020

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

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

#devfest2020
#gdgtaipei

Johnny Sung

October 17, 2020
Tweet

More Decks by Johnny Sung

Other Decks in Programming

Transcript

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

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

    •Future / Promise (Callback chaining)(類似 JavaScript) •Stream Dart 語⾔特性
  6. 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 範例
  7. 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 範例
  8. 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 範例
  9. @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 範例
  10. •強型別,需事先宣告(類似 Java, C#) •物件導向 •async await(類似 C#, JavaScript) •Future /

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

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

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

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

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

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

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

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

    AlertDialog BottomSheet Cupertino CupertinoApp CupertinoPageScaffold CupertinoActivityIndicator CupertinoButton ... CupertinoDialog CupertinoActionSheet
  19. 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
  20. (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
  21. (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 ... }); }); } }
  22. Future fetchData().then((result) { print(result); }).catchError((e) { print(e); }); Future<String> fetchData()

    async { return Future.delayed(Duration(seconds: 2), () { return 'data'; }); } 宣告 使⽤
  23. 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 宣告
  24. 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 寫法
  25. 同步?⾮同步? 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); }); ⾮同步寫法 同步寫法
  26. 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
  27. 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(); } }, );
  28. Stream Stream<int> sampleOfStream() async* { yield 1; yield 2; yield

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

    APIs MyResponse response = await fetchAPI(); yield MyLoadedState(); }
  30. 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
  31. 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) { // ... } }
  32. 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(); }), ], ), ); }
  33. 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 {}
  34. 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
  35. 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
  36. 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()); }); }); }
  37. $ flutter clean $ flutter packages pub upgrade $ flutter

    pub run build_runner build https://stackoverflow.com/a/63328916/3663980 調整 pubspec.yaml 執⾏結果
  38. var number: Int? = null var number2: Int = 1

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

    有問號 沒有問號 int? number = null; Dart
  40. Extension Methods extension NumberParsing on String { int parseInt() {

    return int.parse(this); } } var value = '200'.parseInt(); print(value);
  41. 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 為例)