今天一開始要來整理一下昨天新增的檔案,自其它教學中學到的概念,到目前為止我們新增了許多 Activity,又建立了 ExtraConstants,檔案有點多,因此使用資料夾來做分類,在下圖所示的位置,新增兩個 Pakage。
其中一個命名為 Controllers,存放所有的 Activity,另一個為 Utilities 用來存放 ExtraConstants,歸類後的架構:
先前有提到可以使用 data class 的方式進行 Activity 之間值的傳遞,在歸類架構中我們新增一個 Package -> Models,在內建立 Kotlin File/Calss,此檔案內宣告一個 data class 如下圖所示:
注意在類別後方加入介面 Parcelable,同時按下 Alt + Enter 讓 Android Studio 自動實作介面方法,程式碼會自動產生如下:
data class Schedule(
var arctic: Boolean,
var antarctic: Boolean,
var finland: Boolean): Parcelable {
constructor(parcel: Parcel) : this(
parcel.readByte() != 0.toByte(),
parcel.readByte() != 0.toByte(),
parcel.readByte() != 0.toByte()
) {
}
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeByte(if (arctic) 1 else 0)
parcel.writeByte(if (antarctic) 1 else 0)
parcel.writeByte(if (finland) 1 else 0)
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<Schedule> {
override fun createFromParcel(parcel: Parcel): Schedule {
return Schedule(parcel)
}
override fun newArray(size: Int): Array<Schedule?> {
return arrayOfNulls(size)
}
}
}
不用修改任何東西,回到第二頁面就能使用剛剛的資料類別,拿來裝載選項是否選取的資料:
var schedule = Schedule(
swtArctic.isChecked,
swtAntarctic.isChecked,
swtFinland.isChecked)
接著就能使用 putExtra
將此物件傳遞過去 (EXTRA_AURORA_DATA
是新增在 ExtraConstants.kt 的常數)。第三頁面使用 getParcelableExtra()
方法來接受,注意在 <>
中要指定該物件的類型,也就是 data class Schedule。
var schedule = intent.getParcelableExtra<Schedule>(EXTRA_AURORA_DATA)
額外的應用補充:先前我們會先判斷,是否有至少選擇一項才能繼續往下一頁,在第二頁中可以用 if (schedule.arctic || schedule.antarctic || schedule.finland)
判斷。不過更好的方法應該是將判斷寫在 Schedule
類別中,可以有兩種實作方式,一種是透過屬性 getter
另一種則是 fun
方法:
// 屬性必須初始化,所以要 = false
var hasAnyChecked: Boolean = false
get () {
return (arctic || antarctic || finland)
}
fun hasAnyChecked(): Boolean {
return (arctic || antarctic || finland)
}
接著就可以使用這兩種方式來做判斷:
到目前為止的各頁面如圖所示:
Line: 23 測試印出的 Log 如下 (注意作者在這邊更換了一個 TAG 'Test',若之前使用 TAG 'Flow' 在 Logcat 篩選器搜尋列上,記得更換才能看到)。
D/Test: Schedule(arctic=false, antarctic=true, finland=true)
回到應用程式上,第三個頁面還是空的,這裡先放入一個 textView
,在 xml 中原本使用的是 android:text
存放顯示在應用程式畫面上的文字,但在某些情境下,顯示在畫面上的文字會是動態產生 (透過程式語言),在這之前我們不希望任何字樣顯示在該物件上,不過一旦把 android:text
清除掉後,你會發現在預覽視窗中該物件會變得很小,不方便進行設計排版,這時可以利用 tools:text
取代。
一樣在 xml 中新增一個 tools:text
標籤,將文字內容放在這裡就能在設計窗格中看到文字,且實際執行應用程式時,由於值還是空的,所以是看不到這個 textView 的 (該物件還是有在設計的位置,只是沒有內容),透過 tools:text
還有一個好處,我們可以預知動態值的空間,例如下圖中,用地點兩字暫代空間,這樣能方便在版面設計時將文字長度預先考慮進去。
接著到 Design > 工具箱 > Widgets,將一個 ProgressBar 新增至畫面中:
下一個示範是:將第二頁選擇的項目地點顯示到第三頁的畫面上,並且輪播。因此我們先調整一下之前建立的 data class Schedule
,Line: 11 加入一個容器用 <Key, Value>
來盛裝 <地點名稱, 是否選取>
,Line: 21
再加入一個方法將 true
的項目提取主鍵出來,之前設計的 hasAnyChecked
屬性 (Line: 16)稍微調整一下,改用 lambda 方式判斷,如下圖所示。
(hasAnyChecked() 方法因為與同名屬性是做一樣的事情,就移除不用了)
第三頁面 onCreate()
使用剛設計於 Schedule 類別中的 getCheckedValues
,傳送到 showScheduling()
方法。
var schedule: Schedule = intent.getParcelableExtra(EXTRA_AURORA_DATA)
showScheduling(schedule.getCheckedValues())
由於這個方法我們尚未建立,所以在 IDE 會顯示紅字,用滑鼠左鍵點一下紅色部分,按 Alt + Enter,選擇 Create function 選項。
在 showScheduling
方法中,使用 Handler
與 Runnable
來進行畫面的非同步更新,如果只使用迴圈從 results
裡面取值並更新到 textView
的話沒辦法看到輪播過程,讀者可以嘗試看看,會發現只能看到最後一個選擇的項目。
透過下列方式,會以 2.5 秒為間隔,顯示 results
裡的每個值,並且當所有值已經顯示過後,將文字改為完成,並隱藏處理中的圓圈圖示。
private fun showScheduling(results: Array<String>) {
var index = 0
val handler = Handler()
handler.post(object : Runnable {
override fun run() {
if (index < results.count()) {
textView.text = results[index++]
handler.postDelayed(this, 2500)
} else {
textView.text = "完成"
progressBar.visibility = View.INVISIBLE
}
}
})
}
可以將程式執行起來查看結果,有沒有正確的將所有選到的項目都顯示在螢幕上,並且最終呈現會是”完成”的字樣呢?Activity
的課程到此告一個段落,接續要進入 ListView
我們明天見!
資料參考
Kotlin for Android: Beginner to Advanced | Udemy
https://www.udemy.com/devslopes-android-kotlin/Android Tutorial: Update TextView Every Second. Timer
https://www.youtube.com/watch?v=6sBqeoioCHE