# 04/22 Android教學
## Android 專案介紹
### 建立專案
1. Create New Project

2. Template 選擇 Empty Activity

3. 命名為 BMI calculator, 語言選擇 kotlin

:::warning
注意:heavy_exclamation_mark:
Minimum SDK 表示最低兼容版本 選擇的版本如果太新, 則app很有可能無法在其他裝置上運行!!
:::
4. 那就開始我們的kotlin吧~~

---
## 組織方式
通常以Android專案方式瀏覽專案

### 專案結構

* manifest : 存放Android APP 的主要程式檔
* java : 存放專案主要的kotlin程式碼
* res : 存放專案不是程式碼的資源檔案, 例如:使用者UI(Layout)、圖片、文字等等。
#### AndroidManifest.xml
每個Android APP 都會有此檔案, 存放APP的基本資訊(icon、label等)、有哪些 Activity、 Service、 需要用到的權限等等。

#### MainActivity.kt
寫 UI 的 Android APP 一開始會執行的地方, 一開始只有 onCreate() 方法, 載入對應的 Layout。

**專案程式碼** ~~也就是主要戰場~~
寫 UI 的 Android APP 一開始會執行的地方,一開始只有 `onCreate()` 方法,載入對應的 Layout。
```kotlin=
package com.example.bmicalculator
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main) //這邊載入了 activity_main 的 Layout
}
}
```
##### lifecycle

1. 當Activity準備要產生時,先呼叫onCreate方法。
2. Activity產生後(還未出現在手機螢幕上),呼叫onStart方法。
3. 當Activity出現手機上後,呼叫onResume方法。
4. 當使用者按下返回鍵結束Activity時, 先呼叫onPause方法。
5. 當Activity從螢幕上消失時,呼叫onStop方法。
6. 最後完全結束Activity之前,呼叫onDestroy方法。
:point_right: [官方參考](https://developer.android.com/guide/components/activities/activity-lifecycle)
#### activity_main.xml
MainActivity 的介面 Layout 檔案, 可透過圖形化介面編輯器或是直接編輯 XML 方式操作。

1. 調色盤:可拉取需要的元件到 UI 上。
2. 元件樹:顯示元件之間的結構。
3. 設計編輯器:分別在設計(左)和藍圖(右)視角編輯 Layout。前者為App在裝置上面的呈現, 後者為編輯界面。
4. 屬性:可以修改、查看你選擇的元件的屬性。
5. 觀看模式:可切換使用圖形化介面或 XML 編輯等。
---
## BMI 計算器實作
### 版面配置
切換至 activity_main.xml,並使用 XML 編輯模式。

#### 參考範例
```kotli=
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<EditText
android:id="@+id/input_height"
android:layout_width="172dp"
android:layout_height="54dp"
android:layout_marginStart="176dp"
android:layout_marginLeft="176dp"
android:layout_marginTop="96dp"
android:ems="10"
android:inputType="textPersonName"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/Weight"
android:layout_width="94dp"
android:layout_height="43dp"
android:layout_marginStart="56dp"
android:layout_marginLeft="56dp"
android:layout_marginTop="260dp"
android:clickable="false"
android:text="Weight:"
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
android:textIsSelectable="false"
android:textSize="24sp"
app:autoSizeTextType="uniform"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/Height"
android:layout_width="94dp"
android:layout_height="43dp"
android:layout_marginStart="56dp"
android:layout_marginLeft="56dp"
android:layout_marginTop="104dp"
android:clickable="false"
android:text="Height:"
android:textAppearance="@style/TextAppearance.AppCompat.Body2"
android:textSize="24sp"
app:autoSizeTextType="uniform"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<EditText
android:id="@+id/input_weight"
android:layout_width="172dp"
android:layout_height="54dp"
android:layout_marginStart="176dp"
android:layout_marginLeft="176dp"
android:layout_marginTop="244dp"
android:ems="10"
android:inputType="textPersonName"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
```
#### Layout
* `LinearLayout`:以縱向或橫向呈現。
* `RelativeLayout`:以相對位置呈現。
* `ConstraintLayout`:RelativeLayout 的延伸,透過物件自已本身與其它物件之間的約束來決定它的位置。
#### margin
* `android:layout_margin`:本元件離上下左右各元件的外邊距。
* `android:layout_marginStart`:本元件離開始的位置的外邊距。
* `android:layout_marginEnd`:本元件離結束位置的外邊距。
* `android:layout_marginBottom`:本元件離下部元件的外邊距。
* `android:layout_marginTop`:本元件離上部元件的外邊距。
* `android:layout_marginLeft`:本元件離左部元件的外邊距。
* `android:layout_marginRight`:本元件離右部元件的外邊距。

#### 當然也可以自己拉拉看版面~~

id、位置、長寬、字體大小一樣可以從 attribute 裡面直接更改喔~
:::warning
注意:heavy_exclamation_mark:
每一個元件的 attribute 欄位裡面都可以填寫 id 名稱, 為了之後寫程式方便請盡量將他們改成直觀一點的名字!!
:::
### 使用 findViewById
1. 在 layout 中新增 button `android:id="@+id/btn`。id 的格式為 `@+id/你想取的名字`。
`android:text="calculate"`為按鈕上面的字樣。
```kotli=
<Button
android:id="@+id/btn"
android:layout_width="130dp"
android:layout_height="54dp"
android:layout_marginStart="152dp"
android:layout_marginLeft="152dp"
android:layout_marginTop="356dp"
android:text="calculate"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
```
模擬器呈現:

2. 在 MainActivity.kt 中對按鈕進行綁定及操作。
在`setContentView(R.layout.activity_main)`下方加入:
```kotlin=
val cal = findViewById<Button>(R.id.btn)
```
### 新增點擊事件
BMI 計算器在壓下按鈕的那一刻需要達成:
1. 抓取使用者輸入的身高體重
2. 計算出bmi
3. 顯示 (Toast) 計算結果
在 MainActivity.kt 中對按鈕設定OnClickListener,並使用 Toast 顯示訊息, 格式為:
`button的id名稱.setOnClickListener{
}`
#### 參考範例
```kotlin=
package com.example.bmicalculator
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import android.widget.EditText
import android.widget.Toast
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val cal = findViewById<Button>(R.id.btn)
cal.setOnClickListener{
val w = findViewById<EditText>(R.id.input_weight).text.toString().toFloat()
var h = findViewById<EditText>(R.id.input_height).text.toString().toFloat()
h /= 100
val bmi = w / (h * h)
Toast.makeText(this, bmi.toString(), Toast.LENGTH_LONG).show()
}
}
}
```
###### 抓取`textview` 裡面輸入的數值並將其轉為浮點數`.toFloat()`
###### 變數型態:
* `val`:表示不可以更動的值
* `var`:可以更動的數值
```kotlin=
val w = findViewById<EditText>(R.id.input_weight).text.toString().toFloat()
var h = findViewById<EditText>(R.id.input_height).text.toString().toFloat()
```
###### 將計算結果呈現在UI上
* `Toast.LENGTH_LONG` 跳出結果後呈現較長時間
* `Toast.LENGTH_SHORT` 跳出結果後呈現較短時間
```kotlin=
Toast.makeText(this, bmi.toString(), Toast.LENGTH_LONG).show()
```
### 成果展示(模擬器)

---
## 將 APP 在手機上驅動
1. 將手機用傳輸線連線到電腦 ~~廢話~~
2. 打開 設定->關於手機->按下版本號碼(他要你點幾次就點幾次)
3. 確認更改為開發者模式之後再一次進入設定->系統->開發人員選項->開啟USB偵錯
4. 選擇自己的手機後 再一次執行程式
5. 可以結束ㄌ