Flutter Hello world - DashingDigit001/WikiPage GitHub Wiki
Flutter Basic
- Flutter UI
- Flutter Router
- Flutter Provider
- Flutter Animation
- Flutter + Firebase
- Flutter Android Deployment
- 到Flutter 官網下載 Flutter SDK 並解壓縮到想要的位置
- 變更系統環境變數 -> Windows 開始 -> 輸入 "編輯系統環境變數" -> 進階 -> 環境變數 -> Path -> 加入 Flutter SDK bin 的位置 (e.g. D:\flutter\bin)
- 下載 Visual Studio -> 執行 visual studio installer -> 勾選安裝 C++ 桌面開發套件
- 下載並安裝 Android Studio -> 前往 BIOS -> CPU -> 開啟 Virtual Machine Acceleration -> 開啟 Android Studio -> 點擊 Virtual Machine Manager -> Create Virtual Device -> 效能選取 Hardware - GLES 2.0
- VS Code Extention -> Install Flutter
- 檢查是否有尚未安裝的 dependence -> powershell ->
flutter doctor
- VS Code -> Invoke View -> Command Palette
- 輸入 flutter -> 選擇 Flutter: New Project -> 選擇 Application -> 選擇專案要放的位置 -> 輸入專案名字
- 新增 App launcher icon -> google - > app icon generator -> 放入 png ,檔名輸入 "ic_launcher" 產生完後把壓縮黨裡面的資料夾丟到
[project]/android/app/src/main/res/
取代原本的 -> 到AndroidManifest.xml
檢查<application android:icon="@mipmap/ic_launcher"
名稱是否正確 - VS Code 的右下角 status bar -> 選擇要模擬的裝置 -> 在 main.dart 按下 F5
-
Hello World
- 修改 main.dart
import 'package:flutter/material.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({Key? key}) : super(key: key); // This widget is the root of your application. @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', // is not restarted. home: Scaffold( appBar: AppBar( title: const Text('Flutter Demo Home Page'), ), body: const Center( child: Text('Hello World'), ), ), ); } }
-
MaterialApp & Scaffold:
MaterilApp class 是一個很方便的元件,他提供一大堆用來實現 material design 的元件
Scaffold class 是 material design layout 最基本視覺排版元件,materialApp 下第一個元件建議為 Scaffold
return const MaterialApp( home: Scaffold( body: Text('Hello World'), ), );
-
Text: 顯示文字,可以加入參數設定字型、大小、顏色、對齊
Text( 'Hello,How are you?', )
-
Button:
//ElevatedButton建議放在MaterialApp下 ElevatedButton( onPressed:(){print("clicked")}, child:const Text('ElevatedButton'), ) TextButton( onPressed:(){print("clicked")}, child:const Text('TextButton'), )
-
Column
把子元件垂直顯示的 layout 元件
Column( children: const [ Text('Deliver features faster'), Text('Craft beautiful UIs'), Text('Craft beautiful UIs'), ], )
-
Row
把子元件水平顯示的 layout 元件
Row( children: const [ Text('Deliver features faster'), Text('Craft beautiful UIs'), Text('Craft beautiful UIs'), ], )
-
Container
提供設定 padding、margin、寬高、顏色、形狀、角度的元件
child: Container( margin: const EdgeInsets.all(10.0), color: Colors.amber[600], width: 48.0, height: 48.0, ),
-
Stack & Positioned
Positioned 可以設定子元件的位置,而子元件的位置設定值相對於 Stack 自己的邊界
Stack(alignment: AlignmentDirectional.center, children: const [ Text("11"), Text("12"), Text("13"), Text("14"), Text("15454455455"), ])
-
Sizedbox
可以設定自己的寬高的 layout 元件
const SizedBox( width: 200.0, height: 300.0, child: Text('Hello World!'), )
-
Expanded 可以設定自己寬要填滿父元件
Row( children: <Widget>[ Expanded( flex: 2, child: Container( color: Colors.amber, height: 100, ), ), Container( color: Colors.blue, height: 100, width: 50, ), Expanded( child: Container( color: Colors.red, height: 100, ), ), ], )
-
Builder
這是一個工具元件,目的是為了讓子元件可以在父元件建立完成後才建立。
body: Builder( builder: (BuildContext context) { return Center( child: TextButton( onPressed: () { print(Scaffold.of(context).hasAppBar); }, child: Text('hasAppBar'), ), ); }, ),
-
Listview & ScrollBar
Listview 可以捲動的元件
ScrollBar 用來控制 listview 的 scrollbar的元件
Scrollbar( isAlwaysShown: true, child: ListView( children: <Widget>[ Container( height: 50, color: Colors.amber[600], child: const Center(child: Text('Entry A')), ), Container( height: 500, color: Colors.amber[500], child: const Center(child: Text('Entry B')), ), Container( height: 450, color: Colors.amber[100], child: const Center(child: Text('Entry C')), ), ], ), )
-
stateless widget
當你沒有資料要在 widget 生命週期內更改時,就用 stateless widget
-
stateful widget
當你的資料要在 widget 生命週期內更改時,並要通知 UI Render 時,就用 stateful widget
-
setState
當你要更改 state 時要使用這個函式,才可以通知 UI 重新 Render 畫面
class Test extends StatefulWidget { const Test({Key? key}) : super(key: key); @override _TestState createState() => _TestState(); } class _TestState extends State<Test> { var age = 10; @override Widget build(BuildContext context) { setState(() { age = age + 1; }); return Container(); } }
-
-
Provider 提供一個方便管理全域變數的插件
-
ChangeNotifier 建立一個倉庫,存放變數及 gettet、setter,notifyListeners() 是用來提醒全部有使用到全域變數的 widget 更新畫面
class DataModel extends ChangeNotifier { int _count = 0; int get count => _count; void increment() { _count++; notifyListeners(); } }
-
ChangeNotifierProvider
將要使用全域變數的 widget 放在 ChangeNotifierProvider 之下並初始化 ChangeNotifier
void main() { runApp( ChangeNotifierProvider( create: (context) => DataModel(), child: const MyApp(), ), ); }
-
Consumer
透過 ChangeNotifier 提供的 getter 、setter 存取、更改全域變數
class _MyWidgetState extends State<MyWidget> { @override Widget build(BuildContext context) { return Consumer<DataModel>( builder: (context, data, child) { return Row( children: [ ElevatedButton( child: const Text("Click me"), onPressed: () { data.increment(); }, ), Text('Hello' + data.count.toString()) ], ); }, ); } }
-
-
router 切換顯示頁面,有兩種切頁方式
-
直接切頁
TextButton( child: Text('POP'), onPressed: () { Navigator.pop(context); }, ),
-
具名切頁
-
-
-
flutter pub add firebase_core
-
flutterfire configure
-> 會自動創建一個 lib/firebase_options.dart ,內容是 firebase 的基本資料類似於 vue 中的 firebase.json -
import
//main.dart import 'package:firebase_core/firebase_core.dart'; import 'firebase_options.dart';
-
lib/main.dart 修改 main()
void main() async { WidgetsFlutterBinding.ensureInitialized(); await Firebase.initializeApp( options: DefaultFirebaseOptions.currentPlatform, ); runApp(MyApp()); }
-
到 Firebase console -> 專案設定 -> 找到你的 flutter 應用程式 -> 輸入 SHA 憑證指紋 -> 下載 google-services.json -> 放在專案資料夾/android/app 下
-
flutter pub add cloud_firestore
-
import firestore
import 'package:cloud_firestore/cloud_firestore.dart';
-
新增一個 lib/firebaseUtils.dart
//firebaseUtils.dart import 'package:cloud_firestore/cloud_firestore.dart'; class User { late FirebaseFirestore _firestore; late CollectionReference _usersRef; User() { _firestore = FirebaseFirestore.instance; _usersRef = _firestore.collection('users'); } //... }
-
Create
class User{ //... addUser() { _usersRef.add({ 'name': 'John Doe', 'age': 35, 'city': 'Miami5555', 'state': 'FL', 'country': 'USA555', }); } }
-
Read
class User{ //... readUser() { _usersRef.doc('m1gtCAgQb6OAzy0PJHMV').get().then((value) { print(value.data()); }); } }
-
Update
class User{ //... updateUser() { _usersRef.doc('m1gtCAgQb6OAzy0PJHMV').update({ 'name': 'John Doe', 'age': 999, 'city': 'Miami', 'state': 'aaaaa', 'country': 'TW', }); } }
-
Delete
class User{ //... deleteUser() { _usersRef.doc('m1gtCAgQb6OAzy0PJHMV').delete(); } }
-
import firebaseUtils
import './firebaseUtils.dart';
-
修改 main.dart
class _MyAppState extends State<MyApp> { late User _user; @override Widget build(BuildContext context) { _user = User(); return MaterialApp(home: Scaffold(body: Consumer<DataModel>( builder: (context, data, child) { return Row( children: [ ElevatedButton( child: const Text( "Create", ), onPressed: () { _user.addUser(); }, ), ElevatedButton( child: const Text( "Read", ), onPressed: () { _user.readUser(); }, ), ElevatedButton( child: const Text( "update", ), onPressed: () { _user.updateUser(); }, ), ElevatedButton( child: const Text( "Delete", ), onPressed: () { _user.deleteUser(); }, ), Text('Hello' + data.count.toString()) ], ); }, ))); } }
-
- install
firebase_core
and initialize Firebase flutter pub add firebase_auth
-
google login
-
flutter pub add google_sign_in
-
import 'package:google_sign_in/google_sign_in.dart'; Future<UserCredential> signInWithGoogle() async { // Trigger the authentication flow final GoogleSignInAccount? googleUser = await GoogleSignIn().signIn(); // Obtain the auth details from the request final GoogleSignInAuthentication? googleAuth = await googleUser?.authentication; // Create a new credential final credential = GoogleAuthProvider.credential( accessToken: googleAuth?.accessToken, idToken: googleAuth?.idToken, ); // Once signed in, return the UserCredential return await FirebaseAuth.instance.signInWithCredential(credential); }
-
登入
signInWithGoogle();
-
登出
await FirebaseAuth.instance.signOut(); await GoogleSignIn().signOut();
-
預設資料
Keystore name: "debug.keystore"
Keystore password: "android"
Key alias: "androiddebugkey"
Key password: "android"
CN: "CN=Android Debug,O=Android,C=US"
取得 SHA1 key 的步驟
- powershell ->
keytool -list -v -alias androiddebugkey -keystore <debug.keystore 資料夾位置>
-
powershell
輸入flutter build windows
- 到專案根目錄 -> build/windows/runner -> release 資料夾就是 build 出來的執行檔
- 到 Android Studio -> Build -> Generate Signed Bundle/APK
- click Create new -> 取得
keystore(.jks)
並把他放在C:\Users\User\.android
目錄下
所有 Material Design 的元件建議要放在 MaterialApp 之下
元件的變數,可以被用來存取、變更現在的數值,數值會影響元件的表現
這個 widget 的顯示畫面是沒有紀錄狀態的,所以當 stateless 的widget build 完並顯示在畫面上後,即使 class 內的屬性被更改也不會影響已經 Render 出來的 Widget 內的屬性
這個元件的顯示畫面是有紀錄狀態的,當 State class 的屬性更新時,畫面也會隨著 widget 狀態的改變重新 Render
下圖所有方法都可以加入 @override,有使用 @override都要搭配 super.