owned this note
owned this note
Published
Linked with GitHub
# 寒訓App講義
## 前言
> 本講義所有的連結皆可以透過此連結點選,所有需下載的東西也在裡面:
> https://bit.ly/2023WinterApp
> ![](https://i.imgur.com/WgqUEyp.png =150x)
### android app 介紹
手機應用程式是最近十分熱門的一份商機,也是許多工程師必備的技能。不過以目前目前市場來說,手機app開發所使用的程式語言可以分為針對iOS的Swift語言以及針對android的Java或是Kotlin。但是,由於iOS系統的封閉性,如果要開發相關的app,只能在蘋果電腦(Mac)上使用Xcode開發;另外,開發完的app也較難直接安裝到相對應手機上。因此,這次我們主要會進行android app的開發。
### Kotlin 語言介紹
> Kotlin官網:https://kotlinlang.org/
Kotlin 程式語言為 JetBrains 公司所開發的程式語言,是一種在Java虛擬機(JVM)上執行的靜態型別程式語言。其程式碼可以和Java在JVM當中互相相容運作,另外,也支援轉為JavaScript作為前端語言。
Kotlin在這幾年在app界十分火熱,尤其是在2017年的Google開發者大會中,Google宣布在Android上為Kotlin提供最佳支持。換句話說,Google表態希望所有開法者使用Kotlin取代Java作為app開發的主力語言。
Kotlin相對於Java的優勢:
* 設計變得簡潔,並且讓語意清楚
* 避免 NullError
* 容易入門
另外,Kotlin還有一個超級大優勢就是他有Google大神幫他背書,因此開發文件十分齊全,無論是新手或是Java使用者都可以很方便地轉移過來。
### UI 介紹
User Interface(使用者介面,簡稱UI)指的是在一個App當中使用者看到的所有東西以及他的版面配置,例如文字位置、大小、顏色、圖片及按鈕等等。在Android App裡面UI都是用XML所寫的,語法上有點類似HTML和CSS的混合。不過,如果使用Android Studio來開發的話,可以用圖形化介面,也就是直接以滑鼠拖拉的方式來完成UI的設計。
### 學習資源
學習Android基本上有兩大資源
1. 靠Google大神
* 以**Kotlin**、**Android App入門**等關鍵字搜尋,基本上可以找到許多的學習資料,有的寫的都不錯,尤其是在iT邦幫忙或Medium等平台上都有不錯的部落格文章。
> https://clay-atlas.com/blog/2021/05/07/kotlin-cn-tutorial/
> https://ithelp.ithome.com.tw/articles/10233580
2. 靠Google大神
* 前面有提到,Google 希望推動以Kotlin作為主要的App開發語言,因此他自己研發了一整套的免費教材,超推,~~甚至比看這篇講義或聽我上課有用很多倍。~~
> https://developer.android.com/courses/android-basics-kotlin/course
### Android Studio
Android Studio 是由 Google 和 JetBrains 公司合作的IDE,也是 Google 官方推薦使用的IDE。Android Studio 功能十分強大,甚至可以直接在電腦中弄出一台虛擬的 Android 手機出來方便我們進行 app 的測試。所以,我們先來安裝它吧!
### Android Studio 基本教學
Google教學,建議可以直接按照其步驟完成:https://developer.android.com/courses/pathways/android-basics-kotlin-two
1. 下載安裝檔
- Link: https://developer.android.com/studio
2. 安裝完之後長相
![](https://i.imgur.com/8ZQjLoD.png)
3. 建立第一個專案:按 New Project
![](https://i.imgur.com/rJQvzkp.png)
4. 選擇 empty activity
![](https://i.imgur.com/qVVvSy5.png)
5. 按一下視窗底部的「Next」(下一步)。「New Project」(新增專案) 對話方塊隨即開啟。
![](https://i.imgur.com/VH0ling.png)
以下針對以上進行講解:
* 「Name」(名稱) 是應用程式的名稱。
* 「Package name」(套件名稱) 是 Android 系統用來識別應用程式的名稱。通常,此欄位會預設使用貴機構的名稱,後面加上應用程式的名稱,且全部使用小寫。
* 「Save location」(儲存位置) 是儲存所有專案相關檔案的地方。請記下這些檔案在電腦的位置,以便尋找檔案。你也可以暫時將儲存位置保持原樣。
* 「Language」(語言) 定義了專案要使用的程式設計語言。選「Kotlin」。
* 「Minimum SDK」(SDK 最低版本) 代表可執行應用程式的 Android 最低版本。請從下拉式清單選取 API 19: Android 4.4 (KitKat)。
6. 第一次開啟 Android Studio 時,您會看到三個視窗:
![](https://i.imgur.com/fdzABfw.png)
(1)「Project」(專案) 視窗會顯示專案的檔案和資料夾。
(2)「Editing」(編輯) 視窗可編輯程式碼。
(3)「What's New」(最新消息)
7. 建立手機模擬器
https://bit.ly/3PKmweK
直接看這教學連結了吧,不過,手機請選擇 Pixel6。
![](https://i.imgur.com/wTv4tBl.png)
找不到Device Manager」的人,它在 Android Studio 的選單列中,請依序選取「Tools」(工具) > 「Device Manager」(裝置管理工具)。
![](https://i.imgur.com/tNa964K.png)
8. Android Studio 檔案結構介紹
![](https://i.imgur.com/6jJcf5k.png)
在res資料夾中,會有一些像是圖片、版面配置、UI等等的東東。
而程式碼則都在app資料夾當中。
## Kotlin 語法教學
Kotlin語法十分簡單好上手,網路上資源也相當的多,如果想要自學的話推薦項Google大神求助或是照Google大神的教學包來學習。
另外,這篇文章寫得也不錯:https://clay-atlas.com/blog/2021/05/07/kotlin-cn-tutorial/
基本上,Kotlin除了可以用在App上面,也可以像python或C++一樣直接拿來寫一般的程式,安裝Kotlin環境的方式就不在此贅述了,有興趣的可以自己上網搜尋;基本上,安裝Android Studio時Kotlin環境就已經會安裝完成了。
不過,學語法就直接用IDE來跑,其實有點可怕。因此,我們可以先用一些稱為 Kotlin Playground 的線上編輯器作為測試。
> Kotlin Playground (provided by Google)
> https://developer.android.com/training/kotlinplayground
> Kotlin Playground (provided by kotlinlang.org)
> https://play.kotlinlang.org/
![](https://i.imgur.com/vk3eNZz.png)(應該不用一個一個講功能了吧w)
以下開始正式介紹Kotlin的語法。
### Hello World
```kotlin=
fun main() {
println("Hello, world!!!")
}
```
這是一個Kotlin的 Hello World 程式碼,我們可以看到幾個重點:
1. 可以不加分號
2. 用fun關鍵字宣告函數
3. 和C++一樣要有main函數
4. 用`println()`輸出並且換行
5. 可以改用`print()`,就不會自動換行
### 變數
#### 變數型態
https://kotlinlang.org/docs/basic-types.html
注意事項:Kotlin所有變數類別**首字母皆大寫**
* 整數類別:(做講義的幫我轉表格感謝)
![](https://i.imgur.com/onkZd2A.png)
* 浮點數型態(由大到小): `Double`, `Float`
* 字元型態:`Char`
* 布林值型態:`Boolean`
* 字串:`String`
#### 變數宣告
Kotlin提供兩種變數,分別為`val`和`var`
* `val`代表value,代表此變數只讀不寫(除了初始化不能用`=`符號)
* `var`代表variable,就是一般的變數。
變數的宣告方式如下:
`var 或 val 關鍵字` `變數名稱` `:` `型態` `=` `初始值`
例如:
```kotlin=
val a: Int = 10
var b: String = "I am so weak."
val c: Float = 1.0 + 3.0
```
有初始化的變數也可以省略`型態`部分,這時會很像JS的變數宣告,例如:
```kotlin=
var a = 10
```
補充:要注意的是kotlin裡面也有`const`關鍵字,用來宣告常數。
### 輸入
Kotlin的輸入較少使用,這邊只是做個補充。
使用 `readLine()`可以讀取一整行成字串,但若要像C++的cin一樣,可以使用 `import java.util.Scanner`
例如以下獲取整數輸入的範例
```kotlin=
import java.util.Scanner
fun main() {
val read = Scanner(System.in)
println("請輸入你的年齡:")
var age = read.nextInt()
println("你的年齡是:"+age)
}
```
### 條件
> https://ithelp.ithome.com.tw/articles/10194336
有 `if` 和` when` 兩種用法。
基本的if用法和C++一致:
```kotlin=
val count = 10
if (count < 5) {
println("太少")
} else if (count > 5) {
println("太多")
} else {
println("剛剛好")
}
```
神奇的是,Kotlin中的if可以有回傳值。每個區段的最後一行的值,會被當作若執行到該區段會讓整個語句回傳的值:
```kotlin=
var score: Int = 85
var grade: String = if(score<=100 && score>80){
"A"
}else if(score<=80 && score>=60){
"B"
}else{
"C"
}
println("Grade: $grade")
//印出 Grade: A
```
`when`有點類似`switch-case`:
```kotlin=
when{
條件一 -> {
//如果條件一成立就執行區塊,反之繼續判斷條件二
}
條件二 -> {
//如果條件二成立就執行區塊,反之繼續判斷條件三,以此類推
}
else -> {
//如果以上的條件都不符合,就執行這個區塊
}
}
```
範例:
```kotlin=
var score: Int = 85
var grade = ""
when{
score<=100 && score>80 -> grade = "A"
score<=80 && score>=60 -> grade = "B"
else -> grade = "C"
}
```
```kotlin=
var score: Int = 85
var grade: String = when{
score<=100 && score>80 -> "A"
score<=80 && score>=60 -> "B"
else -> "C"
}
```
### 迴圈
很簡單,自己看:
```kotlin=
// for (節錄自 Kotlin 官方教學程式碼)
val names = listOf("Anne", "Peter", "Jeff")
// 會接續印出 Anne 、 Peter 、 Jeff
for (name in names) {
println(name)
}
// 會接續印出 0 到 10
for (x in 0..10) println(x)
// 會接續印出 0 到 9
for (x in 0 until 10) println(x)
// 會接續印出 0, 2, 4, 6, 8
for (x in 0 until 10 step 2) println(x)
// 會接續印出 10, 8, 6, 4, 2, 0
for (x in 10 downTo 0 step 2) println(x)
// 會接續印出 0: Anne, 1: Peter, 2: Jeff
for ((index, value) in names.withIndex()) {
println("$index: $value")
}
// while (節錄自 Kotlin 官方教學程式碼)
// 會接續印出 0 到 9
var x = 0
while (x < 10) {
println(x)
x++
}
// 標籤型的 continue 和 break 用於跳出外層迴圈 (節錄自 Kotlin 官方教學程式碼)
outer@ for (n in 2..100) {
for (d in 2 until n) {
if (n % d == 0) continue@outer
}
println("$n is prime")
}
```
###### (source: https://ithelp.ithome.com.tw/articles/10233580)
可以看到 `(1..10)`為range語句,會產生一個1~10的range。
### 亂數
https://andyludeveloper.medium.com/kotlin-%E5%B0%8F%E6%92%87%E6%AD%A5-8-%E5%9B%9B%E5%80%8B%E7%94%A2%E7%94%9F%E9%9A%A8%E6%A9%9F%E6%95%B8%E5%AD%97%E7%9A%84%E6%96%B9%E6%B3%95-5fa905be5981
```kotlin=
Random.nextInt() // 產生一個Int亂數
Random.nextFloat() // 產生一個Float亂數
Random.nextInt(1, 10) // 產生一個1到10的亂數
(1..10).random() // 產生一個1到10的亂數
```
### 函數
定義方式:
```kotlin
fun [函式名稱]([參數 1 名稱]: [參數 1 型態]): [回傳型態] {
[內容]
}
```
範例:
```kotlin=
fun BMI(val w: Float, val h: Float): Float {
retunr w/(h*h);
}
// 如果函式只有一行 return 的話,可簡寫成等式
fun happyBirthday2(name: String, age: Int) =
"Happy ${age}th birthday, $name!"
```
### class
建議直接看這一篇教學,這裡礙於版面與教學時間限制將不詳述。
> 在 Kotlin 中使用類別和物件
https://developer.android.com/codelabs/basic-android-kotlin-compose-classes-and-objects?hl=zh-tw#0
### collection
類似C++的STL,包含Array、List、Set、Map等等。詳細列表如下:
![](https://i.imgur.com/YinSrcg.png)
> 張成家我直接幫你把上面表格打成Latex原始碼了
```
\begin{table}[]
\begin{tabular}{llll}
名稱 & 中文名稱 & 備註 & 教學網址 \\
Array & 陣列 & 長度固定 & https://ithelp.ithome.com.tw/articles/10237401 \\
List & 清單 & 長度\&內容不可變 & https://ithelp.ithome.com.tw/articles/10238930 \\
MutableList & 可變清單 & 長度\&內容可變 & \\
Set & 集合 & 內容不可變、內容不重複 & https://ithelp.ithome.com.tw/articles/10239409 \\
MutableSet & 可變集合 & 內容可變、內容不重複 & \\
Map & 就是Map & 鍵(Key)值(Value)對照 & https://ithelp.ithome.com.tw/articles/10240148 \\
MutableMap & 就是可變Map & 內容可變 &
\end{tabular}
\end{table}
```
今天會用到的只有MutableSet,Set和MutableSet是一個按照加入順序進行排列、沒有重複值的集合。今天會用到的語法如下:
#### 宣告
用`mutableSetOf()`函數:
```kotlin=
val muSet = mutableSetOf("Jim", "Sue", "Sue", "Nick", "Nick")
// 只會存放不重複的 Jim, Sue, Nick
val SetOfAges: MutableSet<int> = mutableSetOf(31, 25, 10, 32, 12)
```
若要宣告空的:
```kotlin=
val emptyMutableSet = mutableSetOf<String>()
```
#### 取值、亂數取值
```kotlin=
muSet.elementAt(0) // "tim"
println(muSet.random()) // 亂數輸出一個
var returnValue = muSet.randomOrNull() // set沒東西時會回傳null
```
#### 取大小&修改&刪除
```kotlin=
// 印出 set 大小
println(muSet.size)
// 在 set 最後面加入
muSet.add("Bob")
// 在 set 最後面加入一堆 data
muSet.addAll(listOf("a", "b", "c"))
// remove 某資料
muSet.remove("tim")
// 清除所有
muSet.clear()
```
## UI 基礎教學
應用程式的使用者介面 (UI),是指畫面上顯示的文字、圖片、按鈕及其他多種元素。它不僅是應用程式向使用者顯示內容的方式,也是使用者與應用程式互動的方式。
這些元素每個都是所謂的 View。您在應用程式畫面上看到的內容幾乎都是 View。Views 可以是互動元素,例如可點擊的按鈕或可編輯的輸入欄位。
### 版面配置編輯器
這裡是Android對於新手最友善的一個功能了。只需要透過拖拉即可將東西放到相對應的位置。
從左邊專案資料夾中選擇 res/layout/activity_main.xml 即可編輯預設的版面配置。
在app當中,UI都是使用xml檔案進行記錄的。
如果打開activity_main.xml之後沒有看到版面配置編輯器,可在右上角找到這個地方
![](https://i.imgur.com/mhONZEO.png)
請選擇Design
版面配置編輯器的截圖長相:
![](https://i.imgur.com/xC9NFMd.png)
* 左側標記 (1) 的地方是「Project」(專案) 視窗
* 畫面中央會顯示 (4) 和 (5) 兩個繪圖,分別代表應用程式的螢幕版面配置。
* 左側標記 (4)為「Design」(設計) 檢視畫面,會顯示應用程式執行時呈現的近似效果。
* 右側標記 (5) 的視窗代表「Blueprint」(藍圖) 檢視畫面
* 標記 (2) 的「Palette」(區塊面板) 視窗有各種你可以使用的views
* 標記 (3) 的「Component Tree」(元件樹狀結構) 是另一種螢幕檢視畫面方式,列出螢幕的所有檢視畫面。
* 右邊(6)視窗是「屬性」(Attributes),顯示了 View 的各種設定,可在這裡加以變更。
### 今天會用的View:
![](https://i.imgur.com/m1IolyI.png =300x)
* TextView 文字方塊
* Button 按鈕
* ImageView 圖片
* EditText 輸入方塊(位在Text選單的plain text)
### View怎麼用:
#### 1. 拖到畫面中
* 就,拖過去
#### 2. 固定位置
* 以我們隨邊拖移一個按鈕和一個TextView為例,你可以看到當我們選取物件時,四邊上會有四個圓圈圈。你可以將這四個箭頭拉出去,接到牆上或是其他物件上,這樣會產生彈簧樣子的圖案,代表你靠了這些彈簧定義了物件的相對位置限制。
* ![](https://i.imgur.com/2MVMICj.png)
#### 3. 調整設定
點選一個物件之後,你可以在右邊的attribute視窗當中,調整這個物件的一些相關事務及設定。
![](https://i.imgur.com/I99bgPs.png =200x)
TextView 常用的設定如下:
* id: 就是id,每一個物件都應該有一個專屬好認的id,請用容易記得與分辨的名字,因為等等寫程式時會使用id來分辨物件
* text: 顯示的字
* visibility: 顯示與不顯示
* layout_width 和 layout_height: 寬度及高度,wrap_content代表根據內容大小自動調整。
* textSize: 文字大小
* textColor: 文字顏色
* fontFamily: 字型
* textStyle: 樣式(粗體之類的)
* textAlignment: 對齊方式
另外,如果有設定的旁邊有扳手的圖案![](https://i.imgur.com/M49nA7y.png =x20),代表此項設定是給開發者看的,實際模擬器在跑時看不到。例如,以下設定方式可以讓你在android studio裡面看到這個物件,但是實際執行app時使用者看不到。
![](https://i.imgur.com/VEfrjGx.png)
另外,這個區域可以針對剛剛彈簧做進一步設定:
![](https://i.imgur.com/i82Z7mP.png =250x)
修改其數值代表最少該側我要留多少空間,為0則代表允許緊貼。
> ![](https://i.imgur.com/mNkIhcF.png)
> 修改為60,25時的長相
其他種類views的設定也都大同小異,~~基本上和用ppt很像~~,多摸索幾次就會了。
### Button的使用
Button基本上就是按鈕,可以按下去的那種(廢話)。
使用方式和TextView大同小異。
### imageView的使用
ImageView為UI當中要使用圖片所用的view。在android studio中,要使用圖片必須經過兩個步驟。
#### 1. 將圖片匯入為drawable
首先,請到這裡下載今天會用到的所有圖片:https://bit.ly/2023WinterApp
接下來,點選resource manager
![](https://i.imgur.com/s1Z9KQP.png =200x)
加號,然後import drawable。在Android裡面,drawable指的是可以被畫到螢幕上的東西,包含圖片檔。
![](https://i.imgur.com/7oQkBlA.png =300x)
接下來選擇你要上傳的圖片檔,然後按下next,就完成上傳了。
![](https://i.imgur.com/nYrGPzj.png)
![](https://i.imgur.com/izkdMiY.png)
現在,你可以在 res > drawable資料夾中看到你上傳的檔案了
![](https://i.imgur.com/Mm7MNPe.jpg)
#### 2. 建立imageView
回到版面配置編輯器,從左邊工具箱中選擇ImageView,並拖到畫面中。
這時會跳出這個視窗:
![](https://i.imgur.com/a33oMq9.png)
從左側選擇你要用的圖片,就會建立該imageView
### editText的使用
> ![](https://i.imgur.com/RILrkIg.png =250x)
> palette中的Text標籤下,除了TextView以外都是不同種的EditText,不過今天只會用到Plain Text
editText基本上和textView用法差不多,但是,他設定多了一個hint選項,代表使用者尚未輸入內容時會顯示的文字。
而text屬性則為使用者輸入以及可以編輯的文字。
> editText在模擬器中長相:
![](https://i.imgur.com/xqCrMMG.png =x400) ![](https://i.imgur.com/hJxujtp.png =x400)
### xml檔案
剛剛有說過,實際上的UI是使用XML檔案紀錄的。XML是一種標記語言,語法上類似css。
![](https://i.imgur.com/mhONZEO.png)
我們透過以上切換到code,可以看到如以下之長相。我們可以發覺,所有我們動過的屬性設定皆會被以文字方式記錄下來。
![](https://i.imgur.com/mBoMvVX.png =x500)
切換到split標籤的話我們可以同時看到程式碼與UI的預覽。
![](https://i.imgur.com/TK1Yf8r.png)
你可以嘗試從XML檔案直接修改Button的text屬性,你就會發覺按鈕上顯示的文字被你修改了。
## UI 和 Kotlin 的整合
現在我們已經會使用Kotlin以及UI了,我們可以嘗試將兩者整合起來,以完成我們的app。
首先,我們可以從檔案夾中找到 MainActivity.kt 這個檔案(位於 app/java/com.example.application_name中)。這個檔案就是我們app會執行的主程式。
我們可以看到,Android studio已經幫我們寫好預設的模板了。
其中 onCreate函數就是app會自動執行的main函數。
![](https://i.imgur.com/P6tTnQf.png)
### 開啟自動import功能
在我們用撰寫app程式碼時,常常會要用到許多的函式庫。這時,若開啟android studio的自動import功能便會方便許多。
https://www.geeksforgeeks.org/what-is-the-shortcut-to-auto-import-all-in-android-studio/
Step 1: 點選File > Settings
![](https://i.imgur.com/cXeKkJ2.png =250x)
Step 2: 點選 Editor > General > Auto Import
把Insert imports on paste改成Always
![](https://i.imgur.com/0qQ3s6g.png)
Step 3: 把java和kotlin的Add unambiguous imports on the fly打勾
![](https://i.imgur.com/VM6VpPT.png)
### Toast.makeText()
原本Kotlin的輸出只會顯示在終端機當中,並不會讓使用者在app當中看到。因此,我們可以使用toast來在手機當中跳出提示訊息。
常用語法如下:
```kotlin=
Toast.makeText(this, "要顯示的訊息", Toast.LENGTH_SHORT).show()
```
如此一來,便會在螢幕下方出現一個短暫跳出的通知
![](https://i.imgur.com/ZwjJUP9.png =x500)
如果想要學習更多toast的使用方式,可以看這一篇:
https://learnexp.tw/%E3%80%90android%E3%80%91toast-%E5%BF%AB%E9%A1%AF%E5%85%83%E4%BB%B6/
### findViewById
這個函數是將程式碼與UI整合過程中最重要的一步。
使用方式如下:
```kotlin=
val 變數名: View類別 = findViewById(R.id.物件的id)
```
這時,你會得到一個指向UI物件的一個參考變數。
舉例,如果你的UI裡面有一個id為my_button的按鈕,那麼你可以這樣寫:
```kotlin=
val a: Button = findViewById(R.id.my_button)
```
這樣一來變數a就會是那個按鈕了。如此一來,你可以透過變數a來存取my_button的屬性。使用方法為`a.屬性名`
例如如果你要輸出Button上面寫的字(text屬性),你可以這樣做:
```kotlin=
val textString: String = a.text.toString()
Toast.makeText(this, textString, Toast.LENGTH_SHORT).show()
```
這一個使用方式尤其在editText上面很好用,因為使用者輸入的數字就會存在editText的text屬性裡面。透過此做法,你就可以讀取使用者輸入的內容了。
### .setText()
如果你要更改一個textView或是editText的文字,可以使用此函數。
使用方式如下:
```kotlin=
val k: TextView = findViewById(R.id.textViewid);
k.setText("hello CKEFGISC")
```
![](https://i.imgur.com/I3rLQ4N.png =x400) ------> ![](https://i.imgur.com/agGjQpK.png =x400)
### setOnClickListener
這個函數主要和按鈕連用,代表當一個按鈕被按下時,要執行什麼程式。
使用方式如下:
```kotlin=
按鈕變數.setOnClickListener{
// 這裡寫被按下之後要執行的東西
}
```
使用例子:
```kotlin=
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val myButton: Button = findViewById(R.id.ButtonId1)
myButton.setOnClickListener{
// 這裡寫被按下之後要執行的東西
Toast.makeText(this, "hahahahaha", Toast.LENGTH_SHORT).show()
}
}
}
```
### handler
簡單來說,就是時間暫停器。在使用app時我們有時候希望某個東西等另一段程式先執行完之後再執行,或是希望等待個秒鐘,就可以用handler。
```kotlin=
val handler = Handler() // 建立handler()
handler.postDelayed( { // 計時器
// 一段時間之後要做的事
}, delayTime) // delayTime單位是毫秒
```
## 實作
今天我們的實作目標是做出一個真心話大冒險的app。這個app要有兩個功能:
1. 有一個旋轉的指針,當按下start按鈕之後,能夠有旋轉指針的動畫,並且停下來後會隨機出現題目
2. 有一個輸入欄和一個按鈕,輸入完之後可以將使用者輸入的問題存入問題清單中,並且在之後顯示。
### 建立專案
請先開啟一個全新的Empty Activity專案,取名為Truth_or_Dare。
建立之後,你可以到 `res/values/strings.xml` 檔案中修改app名稱。
![](https://i.imgur.com/becIIAZ.png)
這個檔案主要儲存所有app裡面用到的字串變數。例如先TextView我們都是直接打字串內容,但是一般來說正規做法是在這裡建立字串變數之後,再使用`R.string.變數名`來呼叫。~~但今天先別理他~~
### 建立UI
大致上的UI長相如下(紅字是我取的ID)
指針圖片可以到雲端載點下載。
![](https://i.imgur.com/rIvOflh.png)
### 撰寫程式碼
基本程式的架構如下:
```kotlin=
package com.example.truth_or_dare
import android.os.Bundle
import android.view.animation.RotateAnimation
import android.widget.*
import androidx.appcompat.app.AppCompatActivity
import android.os.Handler
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// 取得各個UI元件
val rollButton: Button = findViewById(R.id.start_button)
val addQuestionButton: Button = findViewById(R.id.add_button)
val questionTextBlock: TextView = findViewById(R.id.question)
val inputTextBlock: EditText = findViewById(R.id.text_input)
val rotateArrowImage : ImageView = findViewById(R.id.spinnerImage)
val questionSet: MutableSet<String> = mutableSetOf<String>(
"測試問題一",
"測試問題二"
) // app題目清單
rollButton.setOnClickListener {
// 開始轉動按鈕被按下之後要執行的程式
}
addQuestionButton.setOnClickListener {
// 新增問題按鈕被按下之後要執行的程式
}
}
```
### 轉動動畫的程式碼
轉動動畫可以使用kotlin內建的Animation完成,使用方法如下
```kotlin=
val am = RotateAnimation(開始角度, 結束角度,
RotateAnimation.RELATIVE_TO_SELF, 旋轉x座標中心,
RotateAnimation.RELATIVE_TO_SELF, 旋轉y座標中心) // 建立動畫物件,注意,角度要用Float型態
am.duration = 旋轉時間 // 設定旋轉時間
am.setFillAfter(true) // 設定旋轉完後停在該角度
myImageView.startAnimation(am) // 將myImageView以am動畫執行
```
以下是一個實作範例:
```kotlin=
val am = RotateAnimation(0.0F, 720.0F,
RotateAnimation.RELATIVE_TO_SELF, 0.5F,
RotateAnimation.RELATIVE_TO_SELF, 0.5F)
// 從0度到720度,共轉兩圈
// 轉動中心在圖片的(50%, 50%)位置,即原本圖片的中心
am.duration = 2000
am.setFillAfter(true)
rotateArrowImage.startAnimation(am)
```
### 完整功能1實作程式碼
```kotlin=
var startDegree = 0.0f // 記錄目前指針的角度
var endDeg = 0.0f
rollButton.setOnClickListener {
// 跳出提示訊息
Toast.makeText(this, "開始旋轉!", Toast.LENGTH_SHORT).show()
// 旋轉動畫
var rotateDeg : Int = (1..360).random() // 要旋轉幾度
rotateDeg += (3..6).random() * 360 // 多加幾圈提高動畫效果
endDeg = startDegree + rotateDeg; // 結束的角度為當前角度加上要旋轉的角度
val am = RotateAnimation(startDegree, endDeg,
RotateAnimation.RELATIVE_TO_SELF, 0.5F,
RotateAnimation.RELATIVE_TO_SELF, 0.5F)
val spinTime : Long= (rotateDeg*3).toLong() // 轉多久
am.duration = spinTime
am.setFillAfter(true)
rotateArrowImage.startAnimation(am)
startDegree = endDeg % 360 // 更新起始角度數值
val handler = Handler() // 建立handler()
handler.postDelayed( { // 計時器
// 出現提問
var chosenQuestion = questionSet.random()
while (chosenQuestion == questionTextBlock.text) { // 避免問題和上一題重複
chosenQuestion = questionSet.random()
}
questionTextBlock.setText(chosenQuestion)
}, spinTime)
}
```
### 完整功能2實作程式碼
```kotlin=
addQuestionButton.setOnClickListener {
val stringInTextField = inputTextBlock.text.toString()
if (stringInTextField.isNotEmpty()) {
questionSet.add(stringInTextField)
Toast.makeText(this, "成功新增問題", Toast.LENGTH_SHORT).show()
} else {
Toast.makeText(this, "請先輸入內容", Toast.LENGTH_SHORT).show()
}
inputTextBlock.setText("") // 清空文字輸入欄
}
```
### 完整答案:
本次app完整專案已經放置在Github上面
可以透過雲端載點:https://bit.ly/2023WinterApp 中的Link文件,或直接點選以下連結取得。
[專案連結](https://github.com/AaronWu-train/Truth_or_Dare)
[MainActivity.kt (Kotlin程式碼)](https://github.com/AaronWu-train/Truth_or_Dare/blob/main/app/src/main/java/com/example/truth_or_dare/MainActivity.kt
)
[activity_main.xml (UI)](https://github.com/AaronWu-train/Truth_or_Dare/blob/main/app/src/main/res/layout/activity_main.xml )
## 建立apk檔案
製作app的最後一步,便是建立真正的安裝檔,並且安裝在自己的手機上!
apk檔案為android的安裝檔格式,Android App內建支援非常簡單的方式建立apk檔。
只要在工具列點選Build -> Build Bundle(s) / APK(s) -> Build APK(s),
apk檔案就編譯完成了!
![](https://i.imgur.com/81hDls1.png =300x)
完成後,右下角會跳出一則訊息,點選Locate,電腦便會從檔案總管顯示該檔案。或是可以自己到以下路徑尋找:`專案資料夾/app/build/outputs/apk/debug`
![](https://i.imgur.com/RX4Det5.png =x50)
![](https://i.imgur.com/xZcaZs7.png =x200)
接下來,你只要用任何你想得到的方式(Discord、Line、雲端)將該檔案從電腦傳送到你的手機當中,就可以安裝完成了!
## 結語
以上就是這一次寒訓app課程的全部了,希望大家都學會建立自己的app了。
另外,講師寫的app安裝檔也已經放到雲端載點了,大家也可以自行上去下載。
有其他問題的話都歡迎詢問AaW喔!