KEMBAR78
Flutter 是什麼?用 Flutter 會省到時間嗎? @ GDG Devfest2020 | PDF
Flutter 是什麼?
⽤ Flutter 會省到時間嗎?
Johnny Sung
•Flutter 是什麼? Dart 語⾔?
•Flutter 畫⾯架構介紹
•Flutter ⼀些常⽤的元件
•⽤ Flutter 開發有什麼要注意的?
•我該⽤原⽣開發還是 Flutter 開發?
•結論
⼤綱
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)
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)
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
•強型別,需事先宣告(類似 Java, C#)
•物件導向
•底線開頭為 private
•async await(類似 C#, JavaScript)
•Future / Promise (Callback chaining)(類似
JavaScript)
•Stream
Dart 語⾔特性
Flutter 畫⾯架構介紹
iOS Plug-ins
Android Plug-ins
Flutter APIs
(UI + Networking)
資料夾結構
•StatefulWidget
•StatelessWidget
Flutter Widget
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 範例
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 範例
StatelessWidget 範例
class MyStateLessWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
// Implement widgets...
return Container();
}
}
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 範例
@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 範例
StatefulWidget 範例
•Container
•SizedBox
•Row / Column
•Text
•Button
•...
常⽤ Flutter Widget
(呃...實在太多了)
•強型別,需事先宣告(類似 Java, C#)
•物件導向
•async await(類似 C#, JavaScript)
•Future / Promise (Callback chaining)(類似
JavaScript)
•Stream
Material Components
•強型別,需事先宣告(類似 Java, C#)
•物件導向
•async await(類似 C#, JavaScript)
•Future / Promise (Callback chaining)(類似
JavaScript)
•Stream
Material Components
•強型別,需事先宣告(類似 Java, C#)
•物件導向
•async await(類似 C#, JavaScript)
•Future / Promise (Callback chaining)(類似
JavaScript)
•Stream
Material Components
•強型別,需事先宣告(類似 Java, C#)
•物件導向
•async await(類似 C#, JavaScript)
•Future / Promise (Callback chaining)(類似
JavaScript)
•Stream
Material Components
•強型別,需事先宣告(類似 Java, C#)
•物件導向
•async await(類似 C#, JavaScript)
•Future / Promise (Callback chaining)(類似
JavaScript)
•Stream
Material Components
•強型別,需事先宣告(類似 Java, C#)
•物件導向
•async await(類似 C#, JavaScript)
•Future / Promise (Callback chaining)(類似
JavaScript)
•Stream
Material Components
•強型別,需事先宣告(類似 Java, C#)
•物件導向
•async await(類似 C#, JavaScript)
•Future / Promise (Callback chaining)(類似
JavaScript)
•Stream
Material Components
•強型別,需事先宣告(類似 Java, C#)
•物件導向
•async await(類似 C#, JavaScript)
•Future / Promise (Callback chaining)(類似
JavaScript)
•Stream
Material Components
vs.
...
常⽤ Flutter Widget
Material
MaterialApp
Scaffold
CircularProgressIndicator
MaterialButton
AlertDialog
BottomSheet
Cupertino
CupertinoApp
CupertinoPageScaffold
CupertinoActivityIndicator
CupertinoButton
...
CupertinoDialog
CupertinoActionSheet
在 Flutter 的世界裡...
萬物皆 Widget
在對應的狀態產⽣對應的畫⾯
Lifecycle
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
(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
(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 ...
});
});
}
}
Future
https://money.udn.com/money/story/5648/4705551
https://www.cna.com.tw/news/firstnews/202007090191.aspx
Future
fetchData().then((result) {
print(result);
}).catchError((e) {
print(e);
});
Future<String> fetchData() async {
return Future.delayed(Duration(seconds: 2), () {
return 'data';
});
} 宣告
使⽤
Future
Future<String> fetchDataA() async {
return Future.delayed(Duration(seconds: 2), () {
return 'dataA';
});
}
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
宣告
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 寫法
•Future 語法
•async / await 語法
同步?⾮同步?
同步?⾮同步?
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);
}); ⾮同步寫法
同步寫法
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
FutureBuilder
萬物皆 Widget
在對應的狀態產⽣對應的畫⾯
•在對應的 狀態 產⽣畫⾯
•狀態
•初始狀態
•載⼊中
•載⼊完成
•有錯誤
FutureBuilder
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();
}
},
);
Stream
Stream
Stream<int> sampleOfStream() async* {
yield 1;
yield 2;
yield 3;
yield 4;
// Do something
await Future.delayed(Duration(seconds: 3));
yield 5;
}
Stream
Stream<MyState> sampleOfFetch() async* {
yield MyLoadingState();
// Do fetch APIs
MyResponse response = await fetchAPI();
yield MyLoadedState();
}
Bloc
•製作定義 Event
•根據對應的 Event 或 State 產⽣資料
Bloc
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
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) {
// ...
}
}
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();
}),
],
),
);
}
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 {}
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
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
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());
});
});
}
個⼈⼼得
•enum ⽀援度不佳
•沒有 null safety(類似 Java, C#)
•Method extensions ⽀援度不佳
Dart 語⾔⼩缺點
https://dart.dev/guides/language/language-tour#enumerated-types
•enum ⽀援度不佳
•沒有 null safety(類似 Java, C#)
•Method extensions ⽀援度不佳
Dart 語⾔⼩缺點
🥳
https://dart.dev/null-safety/understanding-null-safety
Null safety
調整 pubspec.yaml
新增 analysis_options.yaml
$ flutter clean
$ flutter packages pub upgrade
$ flutter pub run build_runner build
https://stackoverflow.com/a/63328916/3663980
調整 pubspec.yaml
執⾏結果
Int? Int
有問號 沒有問號
變數可以為空值 變數不可為空值
var number: Int? = null
var number2: Int = 1
變數名稱 型態 值
變數名稱 型態 值
有問號
沒有問號
Kotlin
int number2 = 1;
變數名稱型態 值
變數名稱型態
值
有問號
沒有問號
int? number = null;
Dart
•enum ⽀援度不佳
•沒有 null safety(類似 Java, C#)
•Method extensions ⽀援度不佳
Dart 語⾔⼩缺點
Added in Dart 2.9
Extension Methods
extension NumberParsing on String {
int parseInt() {
return int.parse(this);
}
}
var value = '200'.parseInt();
print(value);
https://dart.dev/guides/language/extension-methods
•enum ⽀援度不佳
•沒有 null safety(類似 Java, C#)
•Method extensions ⽀援度不佳
Dart 語⾔⼩缺點
Added in Dart 2.9
Added in Dart 2.7
Flutter 套件
https://pub.dev/
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 為例)
WebView
•Flutter 官網
• https://flutter.dev/
•Flutter 中⽂翻譯
• https://flutter.cn/docs
Flutter 學習資源
⽤ Flutter 會省到時間嗎?
熟悉你的⼯具,熟能⽣巧
就會省到時間
Q & A

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