# APP開發環境配置 下載Android Studio,一路點到底,直到看到這個畫面 https://developer.android.com/studio?hl=zh-tw ![](https://hackmd.io/_uploads/BJWGJT1bp.png) 下載flutter SDK,解壓縮在C槽跟Progrem file以外的地方 https://developer.android.com/studio?hl=zh-tw 設定flutter的環境變數 ![](https://hackmd.io/_uploads/rJSjdAkW6.png) 在Android Studio中的 **Plugins > Marketplace 中搜尋Flutter並安裝** ![](https://hackmd.io/_uploads/HJQ0lakW6.png) 重啟後,便可創建Flutter Project了 ![](https://hackmd.io/_uploads/r1KLMak-a.png) # Flutter Hello World ## 創建專案 選擇New Flutter Project > 選擇Flutter SDK Path ![](https://hackmd.io/_uploads/B1KeI0J-6.png) 決定專案名跟專案位置 ![](https://hackmd.io/_uploads/r11fU01Zp.png) ## 創建模擬器 **點選 Device Manager > Create Device** ![](https://hackmd.io/_uploads/HJEo96JWT.png) 選擇手機型號 ![](https://hackmd.io/_uploads/BJnwsaJbT.png) 選擇Andriod系統版本,通常API Level越高越好,Target 選有Google api的為佳 ![](https://hackmd.io/_uploads/B1SknpJb6.png) 設定模擬器的對話盒 ![](https://hackmd.io/_uploads/HJiWhpk-6.png) 點選這裡即可啟動模擬器 ![](https://hackmd.io/_uploads/SJd9naJ-T.png) ## 撰寫Dart語言程式碼並執行 通常是在lib > main.dart中撰寫的 ![](https://hackmd.io/_uploads/BypNuCJbp.png) 在模擬器啟動的情況下 便可以直接執行main.dart ![](https://hackmd.io/_uploads/HykaYCy-T.png) ![](https://hackmd.io/_uploads/HyZFyyeWa.png) # Dart 語法教學 可以在這邊練習: https://dartpad.dev/? Dart 語法跟C/C++很像,本篇主要強調不同之處 ## 輸出 ```dart void main() { int a=10,b=20; print(a); //輸出單變數 print("$a $b"); //一次輸出多個變數,這邊的"$"負責將物件轉成字串 // 輸出 // 10 // 10 20 } ``` ## 變數 * 共有五種可用的變數型態 1. int 2. double 3. num: 可以同時代表int及double 4. String: S要大寫 5. bool * 注意: Dart語言**不可強制轉型**,需要使用對應的method才能實現型別的互相轉換 * Dart語言的變數其實都是物件,故可執行如下的操作 ```dart int x=50; String y=x.toString(); ``` 使用範例 ```dart void main() { int a=10; //宣告的同時賦值 print(a); //基本輸出 String s; //宣告的時候不賦值,當前狀態為NULL // print(s); //錯誤,根據Dart的Null Safety機制,變數在使用時不可為NULL s='apple'; print(s); //正確 var b=true; //類似C++的auto,自動判斷變數的型態 // b='banana'; //錯誤,var被賦值之後,型態便不可任意轉換 print(b); dynamic c=3.14; //類似C++的auto c='cat'; // 與var不同的是,dynamic被賦值之後,型態還可以再被轉換 print(c); const d=1e9+7; //宣告常數 print(d); // 輸出 // 10 // apple // true // cat // 1000000007 } ``` ### 變數之間的轉型 因為Dart語言不可強制轉型,故提供一系列api提供型態轉換 ```dart void main() { //字串轉整數or浮點數 //.parse()稱作「靜態方法」,不須創建物件即可使用 int a=int.parse('3'); double b=double.parse('3.14'); num c=num.parse('1.414'); print("$a $b $c"); //整數or浮點數轉字串 String s1=a.toString(); String s2=b.toString(); print("$s1 $s2"); //整數、浮點數互轉 int temp1=b.toInt(); double temp2=a.toDouble(); print("$temp1 $temp2"); //輸出 // 3 3.14 1.414 // 3 3.14 // 3 3 } ``` ## 函式 大致上與C++相同 * 使用"[ ]"來框住選擇性傳入參數,選擇性傳入參數通常會放在最後面 ```dart void f(int a, [String s='apple']) { print("f: $a $s"); //輸出多個變數的方法 } void main() { f(10); f(10,'banana'); } // 輸出 // f: 10 apple // f: 10 banana ``` * 還有使用參數名稱來設定值的特殊用法 ```dart //被大括號括住的變數,需使用"指定參數名稱及值"的方式傳入 // 這些變數只能是以下三種宣告方式之一: // 加上"required",代表這個變數一定要被傳入 // 給定一個初始值,這樣就算不傳入該變數也不會是NULL // 加上"?",代表這個變數允許空值 void g({required int a, int b=10, String? s}) { print("g: $a $b $s"); } void main() { g(a:1, b:2, s:'apple'); g(s:'banana', a:10, b:20); //可以亂序傳入 g(a:1); //可以不傳 b 跟 s 的值 // g(10, 'apple'); //錯誤用法 // 輸出 // g: 1 2 apple // g: 10 20 banana // g: 1 10 null } ``` ## 類別 (class) * 沒特別指定的情況下,class內部的變數及函式都是Public的 ### 基本用法 ```dart class Person { //使用 late 關鍵字暫時繞過Null Safety的機制 //允許Non-nullable暫時為空,等等就會賦值 late String name; //class Person中的變數 Person(String inputName) { //constructor,用法同C++ name=inputName; // this.name=inputName; //與上面那行等價 } void printInfo() { //class Person中的方法(method) print(name); } } class Student extends Person { //Student 繼承 Person (使用extends關鍵字) late String studentID; //class Student中的變數 //constructor,super()代表使用Parent的constructor來協助初始化 //使用super()時,需傳入Parent constructor所需的參數 Student(String inputName, String inputID) : super(inputName) { studentID=inputID; } } void main() { var student1=Student('Jason','410410054'); student1.printInfo(); //使用class中的method print(student1.name); //使用class中的變數 //輸出 //Jason //Jason } ``` ### constructor 簡寫 可以直接用class成員去對應的位置接 ```dart Person(String inputName) { name=inputName; } //簡寫後 Person(this.name); ``` ```dart Student(String inputName, String inputID) : super(inputName) { studentID=inputID; } //簡寫後 Student(String inputName,this.studentID) : super(inputName); ``` ### Overwritten 用法 ```dart class Person { late String name; Person(this.name); void printInfo() { print(name); } } class Student extends Person { late String studentID; Student(String inputName,this.studentID) : super(inputName); @override // 這行是編譯註解,供compiler 檢查用 void printInfo() { //重新定義Parent的method print("$name $studentID"); } } void main() { var student1=Student('Jason','410410054'); student1.printInfo(); print(student1.name); //輸出 //Jason 410410054 //Jason } ``` # Flutter 開發實戰 ## hello world 把以下程式碼貼在 lib > main.dart 中即可 ```dart import 'package:flutter/material.dart'; void main() { // 宣告一個Text型別的物件,作為appbar的title //可以想成Text()就是constructor //const 代表使用"const constructor",可以加快執行的速度 var appTitle=const Text('my first flutter app'); // 再宣告一個Text型別的物件,作為appBody的child // 設定這個物件的Style;使用TextStyle()這個constructor來指定文字大小 //這個用法就如同函式中 "使用參數名稱來設定值" 的特殊用法 var displayText=const Text( 'Hello World', style: TextStyle(fontSize: 30), ); //宣告一個Center型別的物件,作為app的body var appBody=Center( child:displayText, ); //宣告一個AppBar型別的物件,作為app的appBar var appbar=AppBar( title: appTitle, ); //宣告一個MaterialApp型別的物件,作為app的主體 var app=MaterialApp( home: Scaffold( appBar: appbar, body: appBody, ), ); //執行app物件 runApp(app); } ``` ## StatelessWidget Flutter 中的物件可以分成兩類: StatelessWidget: 物件內容不隨使用者操作改變 StatefulWidget: 物件內容會隨著使用者操作改變 hello world範例中的app 屬於StatelessWidget,故可以讓這個app"繼承"StatelessWidget ```dart import 'package:flutter/material.dart'; //定義class App,並繼承 StatelessWidget class App extends StatelessWidget { @override // 覆寫StatelessWidget 中的build method Widget build(BuildContext context) { // 宣告一個Text型別的物件,作為appbar的title //可以想成Text()就是constructor //const 代表使用"const constructor",可以加快執行的速度 var appTitle=const Text('my first flutter app'); // 再宣告一個Text型別的物件,作為appBody的child // 設定這個物件的Style;使用TextStyle()這個constructor來指定文字大小 //這個用法就如同函式中 "使用參數名稱來設定值" 的特殊用法 var displayText=const Text( 'Hello World', style: TextStyle(fontSize: 30), ); //宣告一個Center型別的物件,作為app的body var appBody=Center( child:displayText, ); //宣告一個AppBar型別的物件,作為app的appBar var appbar=AppBar( title: appTitle, ); //宣告一個MaterialApp型別的物件,作為app的主體 var app=MaterialApp( home: Scaffold( appBar: appbar, body: appBody, ), ); return app; //回傳app 物件 } } void main() { //執行app物件 //呼叫App的constructor,程式便會回傳一個build完成的App物件 runApp(App()); } ``` ## Text 物件 文字是app中最常見的元素之一,可以由constructor Text()所建立 ```dart import 'package:flutter/material.dart'; class App extends StatelessWidget { @override Widget build(BuildContext context) { var appTitle=const Text('my first flutter app'); var displayText=const Text( 'Hello World', //欲顯示的文字 style: TextStyle( //設定文字樣式 fontSize: 30, //指定文字大小 color: Colors.red, //設定文字顏色 // 可選值: // Colors.blue 等等 // Color(0x002f2f2f) 使用Color物件指定 decoration: TextDecoration.lineThrough, //加上線條 // 可選值: // TextDecoration.underline: 加上底線 // TextDecoration.lineThrough: 加上刪除線 // TextDecoration.overline: 文字上方加一條線 fontWeight: FontWeight.w900, //設定粗細 // 可選值: // FontWeight.w100 ~ FontWeight.w900 backgroundColor: Colors.green, //設定背景顏色,用法同color ), textAlign: TextAlign.center, //設定對齊方式 // 可選值: // TextAlign.center: 置中對齊 // TextAlign.left: 置左對齊 // TextAlign.right: 置右對齊 // TextAlign.justify: 使文字在容器內兩側均勻地對齊,填滿整個行寬 maxLines: 10, //限制該文字最多顯示幾行,多的會直接隱藏 ); var appBody=Center( child:displayText, ); var appbar=AppBar( title: appTitle, backgroundColor: const Color(0xffffff99), //可以指定appbar的背景色 ); var app=MaterialApp( home: Scaffold( appBar: appbar, body: appBody, backgroundColor: const Color(0xffadd8e6), //可以指定app的背景色 ), ); return app; } } void main() { runApp(App()); } ``` ## 連接到真機 debug 1. 前置動作 (安裝 google USB Driver) ![image](https://hackmd.io/_uploads/HJW09yhU6.png) 2. 開啟手機的開發者模式 > 設定 > 關於手機 > 不斷點擊 MIUI 版本直到跳出通知 ![image](https://hackmd.io/_uploads/SJTKjJhLT.png =50%x) ![image](https://hackmd.io/_uploads/Hyhos1n8T.png =50%x) 3. 開啟手機的 USB 除錯模式 > 設定 > 更多設定 > 開發者選項 > USB 偵錯(打開) ![image](https://hackmd.io/_uploads/H1Azh128p.png =50%x) ![image](https://hackmd.io/_uploads/HJeQ4n1nUa.png =50%x) ![image](https://hackmd.io/_uploads/BJdShynLp.png =50%x) 4. 連接上 usb,選擇傳輸檔案 ![image](https://hackmd.io/_uploads/Hyefakn8p.png =50%x) 5. 回到 Android Studio,便會自動找到連接的設備;不須另外開啟手機模擬器便可以直接執行程式 ![image](https://hackmd.io/_uploads/HJDBpkhLa.png)