1. 事前準備
在本程式碼研究室中,您將新增骰子的圖片至現有的 Dice Roller Android 應用程式。請務必先建構 Dice Roller 應用程式的基礎,完成之前的程式碼研究室。
應用程式不會在 TextView
中顯示擲骰子的值,而是骰子擲出點數面的正確圖片。所以應用程式的影像內容會更豐富,並提供更好的使用者體驗。
系統會提供下載骰子圖片的連結,讓您在應用程式中將這些圖片新增為資源。如要編寫要使用哪一張骰子圖片的程式碼,請在 Kotlin 中使用 when
陳述式。
必要條件
- 已完成「建立互動式 Dice Roller 應用程式」程式碼研究室。
- 可寫入控制流程的陳述式 (
if / else
、when
陳述式)。 - 根據使用者輸入內容 (修改
MainActivity.kt
檔案) 即可更新應用程式的使用者介面。 - 可新增點擊事件監聽器至
Button.
- 可新增圖片資源至 Android 應用程式
課程內容
- 如何在應用程式執行時更新
ImageView
。 - 如何根據不同條件自訂應用程式行為 (使用
when
陳述式)。
建構項目
- Dice Roller Android 應用程式,含有擲骰子及更新畫面圖片的
Button
。
需求條件
- 安裝 Android Studio 的電腦。
- 下載骰子圖片需要網路連線。
2. 更新應用程式的版面配置
在這項工作中,您要以顯示擲骰子結果圖片的 ImageView
,取代版面配置中的 TextView
。
開啟 Dice Roller 應用程式
- 在 Android Studio 中,開啟並執行先前程式碼研究室的 Dice Roller 應用程式。您可以使用解決方案程式碼,或您建立的程式碼。
應用程式看起來如下。
- 開啟
activity_main.xml
(「app」(應用程式) >「res」(解析度) >「layout」(版面配置) >「activity_main.xml」)。系統隨即會開啟「Layout Editor」(版面配置編輯器)。
刪除 TextView
- 在「Layout Editor」的「Component Tree」中選取
TextView
。
- 按一下滑鼠右鍵,選擇「Delete」或按下
Delete
鍵。 - 暫時忽略
Button
上的警告。您將在後續步驟中修正這個問題。
新增 ImageView 至版面配置
- 將
ImageView
從「Palette」(區塊面板) 拖曳至「Design」(設計) 檢視畫面,並放置在Button
上方。
- 在「Pick a Resource」對話方塊中,選取「Sample data」下的「avatars」。這是您在下一項工作中新增骰子圖片前,暫時使用的圖片。
- 按一下「OK」。應用程式的「Design」檢視畫面應如下所示。
- 在「Component Tree」中,您會看到兩項錯誤。
Button
不受垂直限制,ImageView
則不受垂直或水平限制。
Button
不受垂直限制,因為您已移除原本置於下方的 TextView
。接著,請在下方放置 ImageView
和 Button
。
調整 ImageView 和 Button 的位置
無論 Button
在什麼位置,ImageView
都必須垂直置於畫面中間。
- 在
ImageView
中加入水平限制條件。將ImageView
的左側連結至父項ConstraintLayout
的左側邊緣。 - 連結
ImageView
的右側與父項的右側邊緣。這會讓父項中的ImageView
水平置中。
- 在
ImageView
加入垂直限制,然後連結ImageView
的頂端與父項的頂端。ImageView
會向上滑動至ConstraintLayout
的頂端。
- 在
Button
中加入垂直限制,然後連結Button
的頂端與ImageView
底部。Button
會向上滑動至ImageView
下方。
- 再次選取
ImageView
並加入垂直限制,然後連結ImageView
的底部與父項的底部。這會讓ImageView
在ConstraintLayout
中垂直置中。
現在所有限制相關警告應已消失。
完成所有操作後,「Design」(設計) 檢視畫面應該如下所示,ImageView
位於中央,Button
則緊靠在下方。
在「Component Tree」中,您可能會看到 ImageView
的警示,指出應在 ImageView
加入內容說明。目前不必擔心這項警示,因為之後在程式碼研究室中,您可以根據顯示的骰子圖片,設定 ImageView
的內容說明。這項變更會透過 Kotlin 程式碼完成。
3. 新增骰子圖片
在這項工作中,您必須下載一些骰子圖片,並新增至應用程式。
下載骰子圖片
- 開啟這個網址下載骰子圖片的 ZIP 檔案至電腦上。等待下載作業完成。
- 在電腦上尋找該檔案 (可能位於「下載」資料夾中)。
- 按兩下 ZIP 檔案,解壓縮檔案。這項操作會建立新的
dice_images
資料夾,內含顯示骰子點數 1 到 6 的 6 個骰子圖片檔案。
新增骰子圖片至應用程式
- 在 Android Studio 中,依序按一下選單中的「View」>「Tool Windows」>「Resource Manager」,或點選「Project」視窗左側的「Resource Manager」分頁標籤。
- 按一下「Resource Manager」下方的「+」圖示,然後選取「Import Drawables」,即可開啟檔案瀏覽器。
- 找出並選取這 6 個骰子圖片檔案。您可以選取第一個檔案,然後按住
Shift
鍵並選取其他檔案。 - 按一下「Open」。
- 依序點選「Next」和「Import」,確認要匯入這 6 項資源。
- 如果成功匯入檔案,應用程式的「Resource Manager」(資源管理員) (「app」(應用程式) >「res」(解析度) >「drawable」(可繪項目)) 中會顯示 6 張圖片。
做得好!在下一個工作中,您將在應用程式中使用這些圖片。
重要! - 在 Kotlin 程式碼中,您可以使用圖片的識別碼參考圖片:
R.drawable.dice_1
R.drawable.dice_2
R.drawable.dice_3
R.drawable.dice_4
R.drawable.dice_5
R.drawable.dice_6
4. 使用骰子圖片
更換範例顯示圖片
- 在「Design Editor」中,選取
ImageView
。 - 在「Declared Attributes」部分的「Attributes」中,找到已設為該顯示圖片工具「srcCompat」屬性。
提醒您,工具「srcCompat」屬性只會在 Android Studio 的「Design」檢視畫面中使用提供的圖片。這張圖片只會在建構應用程式時向開發人員顯示,在模擬器或裝置上執行應用程式時不會顯示。
- 按一下顯示圖片的縮圖預覽。系統會開啟對話方塊,請選擇
ImageView
使用的新資源。
- 選取
dice_1
可繪項目,然後按一下「OK」。
哇!ImageView
占滿整面螢幕。
接著,您可以調整 ImageView
的寬度和高度,避免遮掩 Button
。
- 在「Constraints Widget」下方的「Attributes」視窗中,找出「layout_width」和「layout_height」屬性。這兩項屬性目前設為「wrap_content」,即
ImageView
的高度和寬度與其中的內容 (來源圖片) 相同。 - 請將
ImageView
的寬度改設為固定的 160 dp,並將高度設為固定的 200 dp。按下 Enter 鍵。
ImageView
變小了。
您可能發現 Button
太靠近圖片。
- 在「限制小工具」中,設定上邊界到下邊界並加入 16dp。
「Design」檢視畫面更新後,應用程式看來美觀多了!
按下按鈕時變更骰子圖片
我們已修正版面配置,但還必須更新 MainActivity
類別才能使用骰子圖片。
應用程式中的 MainActivity.kt
檔案目前有一項錯誤。如果您嘗試執行應用程式,就會看到以下建構錯誤:
因為程式碼仍然參考從版面配置刪除的 TextView
。
- 開啟
MainActivity.kt
(「應用程式」>「java」>「com.example.diceroller」>「MainActivity.kt」)
程式碼參考 R.id.textView
,但 Android Studio 無法辨識。
- 在
rollDice()
方法中,選取並刪除參考TextView
的程式碼。
// Update the TextView with the dice roll
val resultTextView: TextView = findViewById(R.id.textView)
resultTextView.text = dice.roll().toString()
- 繼續留在
rollDice()
中,建立名為類型ImageView
的diceImage
的新變數。從版面配置將它設為與ImageView
等化。使用findViewById()
方法,傳入ImageView
、R.id.imageView
的資源識別碼作為輸入引數。
val diceImage: ImageView = findViewById(R.id.imageView)
如果想知道如何找出 ImageView
的精確資源 ID,請查看「Attributes」視窗頂端的「ID」。
在 Kotlin 程式碼中參考這個資源 ID 時,請務必輸入完全相同的內容 (小寫的 i、大寫的 V 且不含空格),否則 Android Studio 會顯示錯誤訊息。
- 新增這行程式碼,測試點擊按鈕時,可否正確更新
ImageView
。擲骰子的點數不一定是「2」,只是使用dice_2
圖片進行測試。
diceImage.setImageResource(R.drawable.dice_2)
以上程式碼會對 ImageView
呼叫 setImageResource()
方法,並傳遞 dice_2
圖片的資源 ID。這會更新畫面上的 ImageView
,並顯示 dice_2
圖片。
rollDice() 方法現在應如下所示:
private fun rollDice() {
val dice = Dice(6)
val diceRoll = dice.roll()
val diceImage: ImageView = findViewById(R.id.imageView)
diceImage.setImageResource(R.drawable.dice_2)
}
- 執行應用程式,確認應用程式執行是否正常。應用程式一開始會顯示只有「Roll」按鈕的空白畫面。
輕觸按鈕後,畫面會顯示點數為 2 的骰子圖片。就是這樣!
您可以輕觸按鈕變更圖片!您離完成不遠了!
5. 擲骰子顯示正確的骰子圖片
當然,骰子的點數不一定是 2。請運用您在「為不同 Dice Roller 新增條件式行為」程式碼研究室學習的控制流程邏輯,讓畫面根據隨機擲骰子的結果,顯示正確的骰子圖片。
開始編寫程式碼前,請編寫一些「虛擬程式碼」來說明應用程式的行為,藉此從概念上思考應用程式應該採取的行為模式。例如:
如果使用者擲出 1,即顯示 dice_1
圖片。
如果使用者擲出 2,即顯示 dice_2
圖片。
以此類推...
上述虛擬程式碼可以根據擲骰子的點數,使用在 Kotlin 中的 if / else
陳述式撰寫。
if (diceRoll == 1) {
diceImage.setImageResource(R.drawable.dice_1)
} else if (diceRoll == 2) {
diceImage.setImageResource(R.drawable.dice_2)
}
...
雖然每個案例的撰寫 if / else
都大同小異。相同的邏輯只需使用 when
陳述式,就能輕鬆表達。這是較簡單的 (程式碼較短) 做法!在應用程式中使用這個方法。
when (diceRoll) {
1 -> diceImage.setImageResource(R.drawable.dice_1)
2 -> diceImage.setImageResource(R.drawable.dice_2)
...
更新 rollDice() 方法
- 在
rollDice()
方法中,刪除以下這行程式碼,也就是每次將圖片資源 ID 設為dice_2
圖片的程式碼。
diceImage.setImageResource(R.drawable.dice_2)
- 以根據
diceRoll
值更新ImageView
的when
陳述式取代。
when (diceRoll) {
1 -> diceImage.setImageResource(R.drawable.dice_1)
2 -> diceImage.setImageResource(R.drawable.dice_2)
3 -> diceImage.setImageResource(R.drawable.dice_3)
4 -> diceImage.setImageResource(R.drawable.dice_4)
5 -> diceImage.setImageResource(R.drawable.dice_5)
6 -> diceImage.setImageResource(R.drawable.dice_6)
}
完成變更後,rollDice()
方法如下所示。
private fun rollDice() {
val dice = Dice(6)
val diceRoll = dice.roll()
val diceImage: ImageView = findViewById(R.id.imageView)
when (diceRoll) {
1 -> diceImage.setImageResource(R.drawable.dice_1)
2 -> diceImage.setImageResource(R.drawable.dice_2)
3 -> diceImage.setImageResource(R.drawable.dice_3)
4 -> diceImage.setImageResource(R.drawable.dice_4)
5 -> diceImage.setImageResource(R.drawable.dice_5)
6 -> diceImage.setImageResource(R.drawable.dice_6)
}
}
- 執行應用程式。按一下「Roll」按鈕,將骰子圖片變更為 2 以外的其他點數。成功了!
最佳化程式碼
若要撰寫更簡單的程式碼,請變更下列程式碼。變更程式碼不會對應用程式的使用者造成明顯的影響,但可以縮短程式碼並減少重複。
您可能已經注意到,呼叫 diceImage.setImageResource()
在陳述式中出現 6 次。
when (diceRoll) {
1 -> diceImage.setImageResource(R.drawable.dice_1)
2 -> diceImage.setImageResource(R.drawable.dice_2)
3 -> diceImage.setImageResource(R.drawable.dice_3)
4 -> diceImage.setImageResource(R.drawable.dice_4)
5 -> diceImage.setImageResource(R.drawable.dice_5)
6 -> diceImage.setImageResource(R.drawable.dice_6)
}
每個案例間唯一的區別是使用的資源識別碼。換句話說,您可以建立變數,儲存使用的資源識別碼。然後,在程式碼中只要呼叫 diceImage.setImageResource()
一次,即可傳入正確的資源識別碼。
- 更換程式碼,以下列取代。
val drawableResource = when (diceRoll) {
1 -> R.drawable.dice_1
2 -> R.drawable.dice_2
3 -> R.drawable.dice_3
4 -> R.drawable.dice_4
5 -> R.drawable.dice_5
6 -> R.drawable.dice_6
}
diceImage.setImageResource(drawableResource)
以下的新概念是 when
運算式可以實際回傳值。使用這個新程式碼片段後,when
運算式會傳回正確的資源 ID,並儲存在 drawableResource
變數中。這樣一來,您就可以使用這個變數更新顯示的圖片資源。
- 請注意,
when
已加上紅色底線。如果將滑鼠遊標懸停在這個運算式上,系統會顯示錯誤訊息:「‘when' expression must be exhaustive, add necessary ‘else' branch」。
發生錯誤的原因在於 when
運算式的值已指派給 drawableResource
,因此 when
必須詳盡無遺,也就是這個運算式必須處理所有可能的情況,才能確保即使您變更為 12 面的骰子,仍一律會傳回值。Android Studio 建議新增 else
分支版本。若要修正錯誤,請將案例的 6
變更為 else
。1
到 5
的情況都相同,但包括 6
在內的所有其他情況都會由 else
處理。
val drawableResource = when (diceRoll) {
1 -> R.drawable.dice_1
2 -> R.drawable.dice_2
3 -> R.drawable.dice_3
4 -> R.drawable.dice_4
5 -> R.drawable.dice_5
else -> R.drawable.dice_6
}
diceImage.setImageResource(drawableResource)
- 執行應用程式,確保應用程式仍可正常運作。請務必充分測試,確保 1 到 6 的所有數字都會與相應的骰子圖片一併顯示。
在 ImageView 上設定適當的內容說明
您目前以圖片取代骰出的點數了,但螢幕閱讀器無法顯示骰出的點數。若要修正這個問題,在更新圖片資源後,請更新 ImageView
的內容說明。內容說明是 ImageView
中顯示的內容相關文字說明,有助螢幕閱讀器描述內容。
diceImage.contentDescription = diceRoll.toString()
螢幕閱讀器可以大聲朗讀這段內容說明,因此如果螢幕上顯示骰子擲出「6」的圖片,就會大聲朗讀內容說明為「6」。
6. 採用完善程式設計做法
建立更實用的啟動體驗
使用者首次開啟應用程式時,應用程式顯示的空白畫面 (「Roll」按鈕除外) 看來很突兀。這可能會導致使用者不清楚應用程式的功能,因此您需要變更使用者介面,在首次啟動應用程式時顯示隨機擲骰子的畫面,並建立 Activity
。這樣一來,使用者就較有可能理解,只要輕觸「Roll」按鈕就能擲骰子。
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val rollButton: Button = findViewById(R.id.button)
rollButton.setOnClickListener { rollDice() }
// Do a dice roll when the app starts
rollDice()
}
加上程式碼註解
在程式碼中新增一些註解,說明您編寫的程式碼有何作用。
完成上述所有變更後,您的 rollDice()
方法會如下所示。
/**
* Roll the dice and update the screen with the result.
*/
private fun rollDice() {
// Create new Dice object with 6 sides and roll the dice
val dice = Dice(6)
val diceRoll = dice.roll()
// Find the ImageView in the layout
val diceImage: ImageView = findViewById(R.id.imageView)
// Determine which drawable resource ID to use based on the dice roll
val drawableResource = when (diceRoll) {
1 -> R.drawable.dice_1
2 -> R.drawable.dice_2
3 -> R.drawable.dice_3
4 -> R.drawable.dice_4
5 -> R.drawable.dice_5
else -> R.drawable.dice_6
}
// Update the ImageView with the correct drawable resource ID
diceImage.setImageResource(drawableResource)
// Update the content description
diceImage.contentDescription = diceRoll.toString()
}
如需完整的 MainActivity.kt
檔案,請參閱下一個步驟的連接的 GitHub 解決方案程式碼連結。
恭喜您完成 Dice Roller 應用程式!您現在可以帶著應用程式,與好友玩一晚!
7. 解決方案程式碼
本程式碼研究室的解決方案程式碼在下方顯示的專案和模組中。
若要取得本程式碼研究室的程式碼,並在 Android Studio 中開啟,請按照下列步驟操作。
取得程式碼
- 按一下上面顯示的網址。系統會在瀏覽器中開啟專案的 GitHub 頁面。
- 在專案的 GitHub 頁面中,按一下「Code」按鈕開啟對話方塊。
- 在對話方塊中,按一下「Download ZIP」按鈕,將專案儲存到電腦。等待下載作業完成。
- 在電腦中找到該檔案 (可能位於「下載」資料夾中)。
- 按兩下解壓縮 ZIP 檔案。這項操作會建立含有專案檔案的新資料夾。
在 Android Studio 中開啟專案
- 啟動 Android Studio。
- 在「Welcome to Android Studio」視窗中,按一下「Open an existing Android Studio project」。
注意:如果 Android Studio 已開啟,請依序選取「File」>「New」>「Import Project」選單選項。
- 在「Import Project」對話方塊中,前往解壓縮專案資料夾所在的位置 (可能位於「下載」資料夾中)。
- 按兩下該專案資料夾。
- 等待 Android Studio 開啟專案。
- 按一下「Run」按鈕 即可建構並執行應用程式。請確認應用程式的建構符合預期。
- 在「Project」工具視窗中瀏覽專案檔案,查看應用程式的設定方式。
8. 摘要
- 使用
setImageResource()
變更ImageView
中顯示的圖片 - 使用
if / else
運算式或when
運算式等控制流程陳述式,處理應用程式中不同的情況,例如在不同情況下顯示不同的圖片。
9. 瞭解詳情
10. 自行練習
請按照下列步驟執行:
- 在應用程式新增另一個骰子,讓一個「Roll」按鈕擲出 2 顆骰子的點數。版面配置中需要使用多少
ImageViews
?這會對MainActivity.kt
程式碼造成什麼影響?
檢查您的工作:
完成的應用程式應該可以正常執行,並顯示兩顆骰子。