Android App

真的假的啦 — 真心話大冒險App

Lecture: 一直來不及備課的鹽亞倫

今天要講什麼勒?

  • Android Studio介紹
  • Kotlin基本語法
  • UI 初探
  • 用程式碼控制 UI
  • 實作 --- 建立一個真心話大冒險App

今天所有東西的連結和要下載的檔案都放在這裡:

https://bit.ly/2023WinterApp

今天最多只能讓大家對於App的開發有著初步的認識,並且完成簡單小型的App設計。

所以不太可能上完課以後你就寫得出傳說對決

如果真的有興趣的話

建議大家自行自學更多進階的技巧喔

Disclamer

最後的成果

App開發基本介紹

Android vs iOS Apps

Android

iOS

  • 開發語言: Java、Kotlin
  • IDE: Android Studio
  • 可以在Windows、macOS、Linux上面開發
  • Android系統具開放性,使用者可以「側載」,App不需要上架
  • 開發語言: Swift
  • IDE: Xcode
  • 只能在mac上開發(其實聽說iPad也可以)
  • 系統封閉,一定要經由App Store

所以今天會教Android啦

Kotlin 語言介紹

  • JetBrains 公司所開發
  • 使用Java虛擬機(JVM)執行
  • 可以和Java互相相容運作
  • Google在2017年表態要用Kotlin取代Java
  • Kotlin優勢:
    • 設計簡潔,語意清楚
    • 避免 NullError
    • 容易入門
    • 有谷歌大神背書

怎麼學習App開發?

  1. 靠Google大神

    • ​​iT邦幫忙或Medium等部落格文章
    • Stackoverflow
    • 搜尋Youtube影片
    • 講義有整理一些講師覺得不錯的文章
  2. 靠Google大神

Android Studio

  •  Google 和 JetBrains 公司合作
  •  Google 官方推薦。
  • 功能十分強大
  • 可以直接在電腦中弄出一台虛擬的 Android 手機出來方便我們進行 app 的測試
  • 常常可以從裡面發現Google新手機的資訊(Google保密真是頂呱呱的)

來安裝吧

安裝完之後長相

建立第一個專案

按 New Project

選擇 empty activity

按一下視窗底部的「Next」(下一步)。

「New Project」(新增專案) 對話方塊隨即開啟。
 

應用程式的名稱,幫我改成Truth_or_Dare

 Android 系統用來識別應用程式的名稱

專案資料夾位置(可用預設值)

程式語言(請選Kotlin)

SDK版本,越舊支援度越高,今天選 API 19: Android 4.4 (KitKat)。

第一次開啟 Android Studio 時,會看到三個視窗:

  1. 「Project」(專案) 視窗會顯示專案的檔案和資料夾。

  2. 「Editing」(編輯) 視窗可編輯程式碼

  3. 「What’s New」(最新消息)(可以直接關掉)

建立手機模擬器

直接照著教學做吧:

https://bit.ly/3PKmweK

手機幫我選 Pixel 6

按這裡可以快速開啟Device Manager

按這裡可以叫出已建立的模擬器

模擬器的使用:

執行程式碼

手機的各種按鈕

Android Studio 檔案結構介紹

有Android模式和project Files模式

Android

  • 整理出常用檔案,東西比較好找
  • 程式碼在app/java資料夾底好
  • 圖檔、UI等資源在res

Project Files

  • 實際各個檔案在電腦裡的儲存位置
  • 東西比較難找到

Kotlin基本語法

Kotlin Playground

  • 簡單的線上寫code環境
  • 練習語法時的好地方

Hello World

fun main() {
    println("Hello, world!!!")
}

可以看到幾個重點:

  • 可以不加分號
  • 用fun關鍵字宣告函數
  • 和C++一樣要有main函數
  • println()輸出並且換行
  • 用print(),就不會自動換行

變數

  • 整數類別:Long, Int, Short, Bite
  • 浮點數型態(由大到小): Double, Float
  • 字元型態:Char
  • 布林值型態:Boolean
  • 字串:String

注意:所有型態首字為大寫

整數

小數

變數宣告

變數宣告關鍵字:

val

var

  • value
  • 此變數只讀不寫
  • 不能修改參考對象
  • (除了初始化不能用=符號)
  • 和UI整合時常用
  • variable
  • 就一般常見的變數

變數宣告方式

var 變數名稱: 型態 = 初始值

或是

val 變數名稱: 型態 = 初始值

val a: Int = 10
var b: String = "I am so weak."
val c: Float = 1.0 + 3.0

有初始化的變數也可以省略型態

var a = 10

輸入

  • 今天不會用到,做個補充而已
  • 用readLine()可以讀一行
  • import java.util.Scanner 之後
  • 可以用類似cin的東西
import java.util.Scanner

fun main() {
    val read = Scanner(System.`in`)
    println("請輸入你的年齡:")
    var age = read.nextInt()
    println("你的年齡是:"+age)
}

條件

if else

val count = 10
if (count < 5) {
  println("太少")
} else if (count > 5) {
  println("太多")
} else {
  println("剛剛好")
}

神奇的是,Kotlin中的if可以有回傳值。

每個區段的最後一行的值,會被當作若執行到該區段會讓整個語句回傳的值:

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

when{
    條件一 -> {
        //如果條件一成立就執行區塊,反之繼續判斷條件二
    }
    條件二 -> {
        //如果條件二成立就執行區塊,反之繼續判斷條件三,以此類推
    }
    else -> {
        //如果以上的條件都不符合,就執行這個區塊
    }
}

When

條件

範例

var score: Int = 85
var grade = ""
when{
    score<=100 && score>80 -> grade = "A"
    score<=80 && score>=60 -> grade = "B"
    else -> grade = "C"
}
var score: Int = 85
var grade: String = when{
    score<=100 && score>80 -> "A"
    score<=80 && score>=60 -> "B"
    else -> "C"
}

一樣可以有回傳值

while

迴圈

範例

// while (節錄自 Kotlin 官方教學程式碼)
// 會接續印出 0 到 9
var x = 0
while (x < 10) {
    println(x)
    x++
}

for

迴圈

蠻多種類的,但很簡單

// 會接續印出 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)

val names = listOf("Anne", "Peter", "Jeff")

// 會接續印出 Anne 、 Peter 、 Jeff
for (name in names) {
    println(name) 
}

range

就...類似python的range

(1..10)

一個1到10的range:

for i in (1..10) {
    print(i)
    print(" ")    
}
// output: 1 2 3 4 5 6 7 8 9 10 

除了for迴圈以外,range可以幹嘛

亂數

Random.nextInt()  // 產生一個Int亂數
Random.nextFloat() // 產生一個Float亂數

Random.nextInt(1, 10) // 產生一個1到10的Int亂數
(1..10).random()      // 產生一個1到10的亂數

函數

定義方式:

fun [函式名稱]([參數 1 名稱]: [參數 1 型態]): [回傳型態] {
    [內容] 
}

 範例: 

fun BMI(val w: Float, val h: Float): Float {
    return w/(h*h);
}

// 如果函式只有一行 return 的話,可簡寫成等式
fun happyBirthday2(name: String, age: Int) =
    "Happy ${age}th birthday, $name!"

類別

class

今天不會用到

但還是

Collection

類似C++的STL

包含Array、Map、Set、List等等

名稱 中文名稱 備註 教學網址
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 內容可變

今天只會用到MutableSet

宣告

用mutableSetOf()函數:

val muSet = mutableSetOf("Jim", "Sue", "Sue", "Nick", "Nick") 
// 只會存放不重複的 Jim, Sue, Nick
val SetOfAges: MutableSet<int> = mutableSetOf(31, 25, 10, 32, 12)

若要宣告空的:

val emptyMutableSet = mutableSetOf<String>()

今天只會用到MutableSet

取值、亂數取值

muSet.elementAt(0) // "tim"

println(muSet.random()) // 亂數輸出一個
var returnValue = muSet.randomOrNull() // set沒東西時會回傳null

今天只會用到MutableSet

取大小&修改&刪除

// 印出 set 大小
println(muSet.size)

// 在 set 最後面加入
muSet.add("Bob")
// 在 set 最後面加入一堆 data
muSet.addAll(listOf("a", "b", "c"))

// remove 某資料
muSet.remove("tim")
// 清除所有
muSet.clear()

練習時間

輸出10階金字塔

練習的答案

fun main() {
    var n = 10
    for (i in 1..n){
        for (j in 1..i){
            print('*')
        }
        print('\n')
    }
}

UI 基礎教學

之一

基本介紹

什麼是UI

  • User Interface
  • 使用者介面,簡稱UI
  • 指App當中使用者看到的所有東西&版面配置
  • ex: 文字位置、大小、顏色、圖片及按鈕
  • 一般用XML寫,語法上類似HTML和CSS的混合
  • Android Studio允許直接以滑鼠拖拉的方式完成UI設計

View

  • 所有東西都是一個View
  • TextView、ImageView、Button等等

先回到剛剛Android Studio建立的專案當中

目前你的畫面應該是這樣子的

此時你編輯器開啟的檔案是MainActivity.kt,也就是之後要寫Kotlin程式碼的位置

點按執行,可以看到一個Hello World的App

這就是一個預設的基本UI長相

版面配置編輯器

  • Android對於新手最友善的一個功能
  • 利用它來修改UI
  • 從左邊專案資料夾中選擇 res/layout/activity_main.xml
  • 該檔案即為主要的UI配置檔案

如果打開activity_main.xml之後沒有看到版面配置編輯器,可在右上角找到這個地方

 

 

 

 

 


請選擇Design

  •  (1) 為「Project」(專案) 視窗
  • 畫面中央會顯示 (4) 和 (5) 兩個繪圖,代表應用程式的螢幕版面配置。
  • 左側標記 (4)為「Design」(設計) 檢視畫面,會顯示應用程式執行時呈現的近似效果。
  • 右側標記 (5) 的視窗代表「Blueprint」(藍圖) 檢視畫面
  • 標記 (2) 的「Palette」(區塊面板) 視窗有各種你可以使用的views
  • 標記 (3) 的「Component Tree」(元件樹狀結構) 是另一種螢幕檢視畫面方式,列出螢幕的所有檢視畫面。
  • 右邊(6)視窗是「屬性」(Attributes),顯示了 View 的各種設定,可在這裡加以變更。

UI 基礎教學

之二

View的使用

常用的 View

今天會用的 View

  • TextView 文字方塊
  • Button 按鈕
  • ImageView 圖片
  • EditText 輸入方塊(位在Text選單的plain text)

View 的使用

  1. 拖到畫面中

  2. 固定位置

  3. 調整設定

以TextView為例

2. 固定位置

這些彈簧定義了物件的相對位置限制

3. 調整設定

 

  • 點選一個物件之後,你可以在右邊的attribute視窗當中,調整這個物件的一些相關事務及設定。

常用的設定如下:

  • id: 每一個物件都應有一個專屬的id,請用容易記得與分辨的名字
  • text: 顯示的字
  • visibility: 顯示與不顯示
  • layout_width 和 layout_height: 寬度及高度,wrap_content代表根據內容大小自動調整。
  • textSize: 文字大小
  • textColor: 文字顏色
  • fontFamily: 字型
  • textStyle: 樣式(粗體之類的)
  • textAlignment: 對齊方式

基本上用法和ppt差不多

亂試幾次就會了

另外,這個區域可以針對剛剛彈簧做進一步設定:

修改其數值代表最少該側我要留多少空間,為0則代表允許緊貼。

修改為60,25時的長相

試試看做出這個版面配置

ID: TitleText

大小:34sp

ID: SubtitleText

大小:20sp

其他View的使用

Button的使用

  • Button基本上就是按鈕,可以按下去的那種
  • 設定調整方式和TextView差不多
  • 怎麼偵測被按下去之後會教

其他View的使用

ImageView的使用

  • 透過ImageView使用圖片檔
  • 要先建立drawable
  • drawable指的是可以被畫到螢幕上的東西
  • ImageView是一個View,可以透過程式決定顯示哪一個drawable

其他View的使用

ImageView的使用

1. 將圖片匯入為drawable

其他View的使用

ImageView的使用

1. 將圖片匯入為drawable

其他View的使用

ImageView的使用

1. 將圖片匯入為drawable

  • 接下來選擇你要上傳的圖片檔,然後按下next,就完成上傳了。

其他View的使用

ImageView的使用

1. 將圖片匯入為drawable

  • 接下來選擇你要上傳的圖片檔,然後按下next,就完成上傳了。

其他View的使用

ImageView的使用

2. 建立imageView

  • 回到版面配置編輯器,從左邊工具箱中選擇ImageView,並拖到畫面中。
  • 這時候要選擇你ImageView要使用的Drawable
  • 這樣就成功建立ImageView了

其他View的使用

editText的使用

  • 輸入文字
  • palette中的Text標籤,除了TextView都是不同種的EditText

  • 今天只會用到Plain Text

  • editText基本上和textView用法差不多
  • 設定多了一個hint選項
  • 代表使用者尚未輸入內容時會顯示的文字。
  • text屬性則為使用者輸入/編輯的內容

其他View的使用

editText的使用

editText在模擬器中長相:

實作時間

做出今天真心話大冒險的UI長相

指針圖片可以在雲端找到

紅字為id

UI 基礎教學

之三

補充:Xml檔案

xml檔案

剛剛有說過,實際上的UI是使用XML檔案紀錄的。

XML是一種標記語言,

語法上類似html,記錄的東西類似css

我們透過以上切換到code,可以看到如以下之長相。

我們可以發覺,所有我們動過的屬性設定皆會被以文字方式記錄下來。

切換到split標籤的話我們可以同時看到程式碼與UI的預覽。

還有很多東西是用xml紀錄的

res/values/strings.xml

記錄字串變數的地方

app_name 指的是手機上icon底下會顯示的名字

用Kotlin控制UI

今天最重要的一步

  • 現在我們已經會使用Kotlin以及UI了
  • 將兩者整合起來,以完成我們的app。
  • 有點類似用js去控制網頁element
  • 等等會介紹多個函數

如何在android studio裡面寫kotlin?

package com.example.helloworldtest1

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) { // main函數
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        // 從這裡接者寫
        
        
        
    }
    // 函數可以宣告在這裡
}

// class 可以宣告在這裡

打開 mainActivity.kt

程式碼都要寫在這裡

其中 onCreate函數相當於main函數

開啟自動import功能

直接看教學

講義

Toast.makeText()

  • 出現在手機下方的彈跳通知
Toast.makeText(this, "要顯示的訊息", Toast.LENGTH_SHORT).show()
  • 效果:

findViewById

  • 將程式碼與UI整合過程中最重要的一步
  • 使用方式如下:

 val 變數名: View類別 = findViewById(R.id.物件的id)
  • 這時,你會得到一個指向UI物件的一個參考變數。

findViewById

舉例,如果你的UI裡面有一個id為my_button的按鈕,那麼你可以這樣寫:

 
 val a: Button = findViewById(R.id.my_button)
  • 這樣一來變數a就會是那個按鈕了。如此一來,你可以透過變數a來存取my_button的屬性
  • 使用方法為 a.屬性名

findViewById

例如如果你要輸出Button上面寫的字(text屬性),你可以這樣做:

val textString: String = a.text.toString()
Toast.makeText(this, textString, Toast.LENGTH_SHORT).show()
  • 以上用法常用於editText
  • 因為使用者輸入的數字就會存在editText的text屬性
  • 如此就可以讀取使用者輸入的內容了

.setText()

用這個方法函數修改UI元件的text屬性

val k: TextView = findViewById(R.id.textViewid);
k.setText("hello CKEFGISC")

setOnClickListener

這個函數主要和按鈕連用,代表當一個按鈕被按下時,要執行什麼程式。

按鈕變數.setOnClickListener{
    // 這裡寫被按下之後要執行的東西
}

setOnClickListener

使用例子:

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

時間暫停器

先等一段時間後再執行一段程式碼

val handler = Handler()    // 建立handler()
handler.postDelayed( {     // 計時器
    // 一段時間之後要做的事
}, delayTime) // delayTime單位是毫秒

實作時間

今天的實作目標

真心話大冒險app

兩大目標:

  1. 有一個旋轉的指針,當按下start按鈕之後,能夠有旋轉指針的動畫,並且停下來後會隨機出現題目
  2. 有一個輸入欄和一個按鈕,輸入完之後可以將使用者輸入的問題存入問題清單中,並且在之後顯示。

剛剛應該已經把UI建立完了吧

接下來直接從撰寫程式碼開始了喔

回到 mainActivity.kt

以下是這次程式碼的大致架構

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 {
            // 新增問題按鈕被按下之後要執行的程式
        }
    }

繪製流程圖

功能一

  • 按鈕被按下
  • 決定旋轉角度
  • 開始旋轉動畫
  • 等到動畫轉完之後:
    • 從題單裡面隨機一題
    • 將id為question的textView
      的text屬性更改為題目的文字

好像沒講過?

繪製流程圖

功能二

  • 按鈕被按下
  • 讀取editView的text屬性
  • 將讀取到的東西存到set裡面
  • 清空editView text屬性的文字

旋轉動畫

轉動動畫可以使用kotlin內建的Animation完成,使用方法如下

val am = RotateAnimation(開始角度, 結束角度,
    RotateAnimation.RELATIVE_TO_SELF, 旋轉x座標中心,
    RotateAnimation.RELATIVE_TO_SELF, 旋轉y座標中心) // 建立動畫物件,注意,角度要用Float型態

am.duration = 旋轉時間  // 設定旋轉時間
am.setFillAfter(true) // 設定旋轉完後停在該角度

myImageView.startAnimation(am) // 將myImageView以am動畫執行

旋轉動畫

使用的範例

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)

來寫完功能一吧

答案

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)
}

來寫完功能二吧

答案

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("")  // 清空文字輸入欄
}
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

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        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預設就有的問題

        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)
        }

        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("")  // 清空文字輸入欄
        }
    }
}

製作安裝檔

apk檔案

  • android app安裝檔
  • android studio可以非常簡單的產生
  • 在工具列點選Build -> Build Bundle(s) / APK(s) -> Build APK(s)
  • 搞定!
  • 選Locate
  • 或是直接去這個位置找apk檔:
  • 專案資料夾/app/build/outputs/apk/debug

得到apk檔案之後?

用任何你知道的方式傳到你的手機

安裝他

完成!!!

成果展示時間

下課啦~

2023建北電資聯合寒訓 --- Android App 教學

By Aaron Wu

2023建北電資聯合寒訓 --- Android App 教學

  • 210