將圖像新增至 Android 應用程式

1. 事前準備

在本程式碼研究室中,您將瞭解如何使用 Image 可組合項將圖片加入應用程式。

必要條件

  • 如何在 Android Studio 中建立及執行應用程式的基本知識。
  • 新增 UI 元素 (例如文字可組合項) 的基本知識。

課程內容

  • 如何在 Android 應用程式中新增圖片或相片。
  • 如何使用 Image 可組合項顯示應用程式中的圖片。
  • 使用 String 資源的最佳做法。

建構項目

  • 強化 Happy Birthday 應用程式的功能,加入圖片。

軟硬體需求

2. 設定應用程式

使用 Android Studio 先前的程式碼研究室開啟 Happy Birthday 專案。

執行應用程式時,畫面應如以下螢幕截圖所示。

fdf3fc55ab1d348a.png

在專案中新增圖片

在這項工作中,您將從網際網路下載圖片並新增至 Happy Birthday 應用程式。

  1. 透過此連結開啟生日卡片應用程式的圖片。
  2. 點選「下載」

1d731e32164fca8a.png

  1. 在圖片上按一下滑鼠右鍵,將檔案命名為 androidparty.png,儲存至電腦。
  2. 請記下您儲存圖片的位置。

舉例來說,您可能將其儲存在「Downloads」資料夾中。

  1. 在 Android Studio 中,依序點選「View」>「Tool Windows」>「Resource Manager」,或按一下「Project」視窗旁邊的「Resource Manager」分頁標籤。

3cda2692405276d.png

3b6c04c505468229.png

  1. 依序點選「+ (Add resources to the module)」>「Import Drawables」

a85b707150fcff9a.png

  1. 在檔案瀏覽器中選取已下載的圖片檔,然後按一下「Open」

這個動作會開啟「Import Drawables」對話方塊。

d64abadd7b79ecf0.png

  1. Android Studio 會顯示圖片的預覽畫面。在「QUALIFIER TYPE」下拉式清單中選取「Density」。後續章節會說明執行這項操作的原因。

限定詞類型設為「density」

  1. 從「VALUE」清單中選取「No Density」

 「VALUE」下拉式選單,顯示已選取沒有 dpi 的選項

Android 裝置有多種螢幕尺寸 (例如手機、平板電腦和電視等),且螢幕的像素大小也不同。這表示如果某部裝置每平方英吋有 160 像素,另一部裝置在相同空間能容納 480 像素。如果您未考慮像素密度的這些變化,系統可能會縮放圖片,導致圖片模糊不清,或者產生占用過多記憶體的大型圖片,或尺寸不正確的圖片。

如果您將圖片調整為大於 Android 系統能處理的大小,系統就會擲回記憶體不足錯誤。如果是相片和背景圖片 (例如目前的圖片 androidparty.png),請將其存放於 drawable-nodpi 資料夾中,以停止調整大小行為。

如要進一步瞭解像素密度,請參閱支援不同的像素密度

  1. 點選「Next」
  2. Android Studio 會顯示存放圖片的資料夾結構。請留意 drawable-nodpi 資料夾。
  3. 按一下「Import(C)」

74d23f98b8018f93.png

Android Studio 會建立 drawable-nodpi 資料夾,用來存放圖片。在 Android Studio 專案檢視畫面中,資源名稱會顯示為 androidparty.png (nodpi)。在電腦檔案系統中,Android Studio 會建立一個名為 drawable-nodpi 的資料夾。

5e5ca441e391929e.png

檔案放在 drawable no dpi 資料夾底下

如果圖片成功匯入,Android Studio 會將圖片新增至「Drawable」分頁下方的清單。這份清單包含應用程式的所有圖片和圖示。您現在可以在應用程式中使用這個圖片。

顯示新加入的圖片

  1. 依序點選「View」>「Tool Windows」>「Project」,或按一下最左側的「Project」分頁標籤,即可切換回專案檢視畫面。
  2. 依序點選「app」>「res」>「drawable」,確認圖片位於 drawable 資料夾。

f95964d9f0ee2dba.png

3. 新增 Image 可組合項

如要在應用程式中顯示圖片,需要有顯示位置。如同使用 Text 可組合函式顯示文字一樣,您也可以使用 Image 可組合函式顯示圖片。

在這項工作中,您要在應用程式中新增 Image 可組合函式、將應用程式圖片設為您下載的圖片、放置圖片並調整大小,讓圖片填滿整個螢幕。

新增可組合函式以加入圖片

  1. MainActivity.kt 檔案的 GreetingText() 函式後方,加上 GreetingImage() 可組合函式。
  2. 將兩個 String 參數傳遞至 GreetingImage() 函式:一個為用於生日祝福語的 message,另一個則為用於署名的 from
@Composable
fun GreetingImage(message: String, from: String) {
}
  1. 每個可組合函式都應接受選用的 Modifier 參數。修飾符可以指示 UI 元素如何在其上層布局內部安排版面配置、顯示或行為。在 GreetingImage() 可組合項新增另一個參數。
@Composable
fun GreetingImage(message: String, from: String, modifier: Modifier = Modifier) {
}

Jetpack Compose 中的資源

資源是程式碼使用的額外檔案和靜態內容,例如點陣圖、使用者介面字串和動畫指示等。如要進一步瞭解 Android 中的資源,請參閱應用程式資源總覽

請您務必將應用程式資源 (如圖片及字串) 與程式碼分開,以便獨立維護這些資源。Android 在執行階段中會根據目前設定使用合適的資源。例如,您可能會想根據螢幕大小提供不同的 UI 版面配置,或是根據語言設定提供不同的字串。

將資源分組

請務必將每種資源存放在專案 res/ 目錄的特定子目錄中。下列為簡易專案的檔案階層範例:

MyProject/
    src/
        MyActivity.kt
    res/
        drawable/
            graphic.png
        mipmap/
            icon.png
        values/
            strings.xml

在這個範例中您可以看到,res/ 目錄包含子目錄中的所有資源,包括圖片資源的 drawable/ 目錄、啟動器圖示的 mipmap/ 目錄,以及字串資源的 values/ 目錄。如要進一步瞭解應用程式資源的使用情況、格式和語法,請參閱資源類型總覽

存取資源

Jetpack Compose 可以存取 Android 專案中定義的資源。您可以透過在專案 R 類別中產生的資源 ID 存取資源。

R 類別是 Android 自動產生的類別,其中包含專案中所有資源的 ID。在多數情況下,資源 ID 與檔案名稱相同。例如,您可以使用此程式碼存取先前檔案階層中的圖片:

R.drawable.graphic

R 是自動產生的類別,drawable 是 res 資料夾中的子目錄,graphic 為資源 ID

在下一個工作中,請使用您在先前工作中新增圖片的 androidparty.png 檔案。

  1. GreetingImage() 函式中,宣告 val 屬性並命名為 image
  2. 您可以透過傳入 androidparty 資源,呼叫 painterResource() 函式。將傳回的值指派給 image 變數。
val image = painterResource(R.drawable.androidparty)

Android Studio 會醒目顯示 .painterResource 程式碼,因為您需要匯入這個函式來編譯應用程式。

82323978341a0bdc.png

  1. 按一下 Android Studio 醒目顯示的 .painterResource
  2. 按一下彈出式視窗中的「Import」,加入 androidx.compose.ui.res.painterResource 的匯入內容。

painterResource() 函式會載入可繪圖片資源,並採用資源 ID (本例中為 R.drawable.androidparty) 做為引數。

  1. 呼叫 painterResource() 函式後,新增 Image 可組合函式,然後傳入 image 做為 painter 的具名引數。
Image(
    painter = image
)

Android Studio 會醒目顯示 Image 程式碼,因為您需要匯入這個函式來編譯應用程式。

e2bead11643e0577.png

如要修正這項警告,請在 MainActivity.kt 檔案頂端加入以下匯入項目:

import androidx.compose.foundation.Image

初始警告現已解決,但如果您將游標懸停在 Image 這個字詞上,Android Studio 會顯示新的警告,指出「None of the following functions can be called with the arguments supplied.」,這是因為提供的引數不符合任何 Image 函式簽章。

ad35f0a40f8fc849.png

我們將在下一節修正這項警告提出的問題。

檢查應用程式是否有無障礙設計

只要遵循無障礙程式設計做法,就能讓所有使用者 (包括身心障礙使用者) 更輕鬆瀏覽應用程式,並與應用程式互動。

Android Studio 提供提示和警示,讓使用者更容易使用您的應用程式。內容說明定義 UI 元素的用途,讓您的應用程式更容易搭配 TalkBack 使用。

但應用程式中的圖片僅供參考,在此特定情況下,針對圖片新增內容說明會較難以搭配 TalkBack 使用。您可將圖片的 contentDescription 引數設為 null,使 TalkBack 略過 Image 可組合項,而無需設定向使用者宣布的內容說明。

  • Image 可組合函式中,新增另一個名為 contentDescription 的引數,並將值設為 null
Image(
    painter = image,
    contentDescription = null
)

預覽 Image 可組合項

在這項工作中,您會預覽圖片可組合項,並在模擬器或裝置上執行應用程式。

  1. BirthdayCardPreview() 函式中,將 GreetingText() 函式呼叫替換為 GreetingImage() 函式呼叫。

您的函式應如此程式碼片段所示:

@Preview(showBackground = true)
@Composable
fun BirthdayCardPreview() {
    HappyBirthdayTheme {
        GreetingImage(
            message = "Happy Birthday Sam!",
            from = "From Emma"
        )
    }
}
  1. 「Design」窗格應會自動更新。如未更新,請按一下 609ccb451d05cf6b.png 進行建構。

請注意,新函式僅包含 Image 可組合函式,但不含 Text 可組合函式,因此不會再顯示文字。

acd47e25eb2a8d55.png

4. 新增 Box 版面配置

Compose 有三個基本的標準版面配置元素,分別是 ColumnRowBox 可組合函式。您在先前的程式碼研究室中學過 ColumnRow 可組合函式,現在您將進一步瞭解 Box 可組合函式。

Box 版面配置是 Compose 標準版面配置元素之一。使用 Box 版面配置將元素堆疊在另一個元素上。Box 版面配置也可讓您設定其包含元素的具體對齊方式。

4d191637aaecf374.png

  1. GreetingImage() 函式的 Image 可組合函式前後新增 Box 可組合函式,如下所示:
@Composable
fun GreetingImage(message: String, from: String, modifier: Modifier = Modifier) {
    val image = painterResource(R.drawable.androidparty)
    Box {
        Image(
            painter = image,
            contentDescription = null
        )
    }
}
  1. 當 Android Studio 顯示提示時,匯入 androidx.compose.foundation.layout.Box 函式。
  2. 新增程式碼,將 modifier 參數傳遞至 Box 可組合函式。
@Composable
fun GreetingImage(message: String, from: String, modifier: Modifier = Modifier) {
    val image = painterResource(R.drawable.androidparty)
    Box(modifier) {
        Image(
            painter = image,
            contentDescription = null
        )
    }
}
  1. Box 可組合函式的結尾呼叫 GreetingText() 函式,並傳入生日訊息、簽名和修飾符,如下所示:
@Composable
fun GreetingImage(message: String, from: String, modifier: Modifier = Modifier) {
    val image = painterResource(R.drawable.androidparty)
    Box(modifier) {
        Image(
            painter = image,
            contentDescription = null
        )
        GreetingText(
            message = message,
            from = from,
            modifier = Modifier
                .fillMaxSize()
                .padding(8.dp)
        )
    }
}
  1. 留意「Design」窗格中更新後的預覽畫面。

畫面上應該會顯示文字和圖片。

背景圖片固定在畫面頂端

  1. 如要讓模擬器或裝置呈現上述變更,請將 onCreate() 函式中的 GreetingText() 函式呼叫替換為 GreetingImage() 函式呼叫。

setContent 區塊應如以下程式碼片段所示:

setContent {
    HappyBirthdayTheme {
        // A surface container using the 'background' color from the theme
        Surface(
            modifier = Modifier.fillMaxSize(),
            color = MaterialTheme.colorScheme.background
        ) {
            GreetingImage(
                message = "Happy Birthday Sam!",
                from = "From Emma"
            )
        }
    }
}

請注意,圖片寬度與畫面寬度相同,但圖片會固定在畫面頂端,畫面底部留有不美觀的空白空間。在下一項工作中,您將填滿畫面的寬度和高度,將圖片放大至填滿整個畫面。

5. 變更不透明度並放大圖片

在這項工作中,您會將圖片放大為全螢幕,美化應用程式的外觀。方法是使用 ContentScale 參數。

調整內容

您已將圖片新增至應用程式中,並放置於定位。現在,您必須調整圖片的調整類型 (如何將圖片大小調整成全螢幕)。

目前有很多 ContentScale 類型可供使用。使用 ContentScale.Crop 參數可統一縮放圖片,維持既有顯示比例,讓圖片的寬度和高度等於或大於畫面的對應尺寸。

  1. ContentScale 引數新增至圖片。
Image(
    painter = image,
    contentDescription = null,
    contentScale = ContentScale.Crop
)
  1. 在 Android Studio 顯示提示時,匯入 androidx.compose.ui.layout.ContentScale 介面。
  2. 查看「Design」窗格。

圖片現在應填滿整個預覽畫面,如以下螢幕截圖所示:

ae1a5ec6b294f466.png

變更不透明度

如要改善應用程式的對比度,請變更背景圖片的不透明度。

Image 可組合函式中加入 alpha 參數,並設為 0.5F

Image(
    painter = image,
    contentDescription = null,
    contentScale = ContentScale.Crop,
    alpha = 0.5F
)

請注意圖片不透明度的變化。

這包含大量程式碼!現在該預覽所有您努力的成果了。

執行應用程式

在裝置或模擬器上執行應用程式。

9d1416521733e8c.png

全螢幕圖片和文字訊息都做得很好。您也變更了圖片的不透明度。

版面配置修飾符

修飾符可用於在 Jetpack Compose UI 元素中裝飾或新增行為。舉例來說,您可以在列、文字或按鈕中新增背景、邊框間距或行為。可組合項或版面配置必須接受修飾符做為參數,才能進行設定。

您已在先前的程式碼研究室中學過修飾符,並使用邊框間距修飾符 (Modifier.padding) 在 Text 可組合函式前後加上空格。修飾符可以執行大量作業,您會在本課程及後續課程中進行體驗。

舉例來說,此 Text 可組合項的 Modifier 引數會將背景顏色變更為綠色。

// Example
Text(
    text = "Hello, World!",
    // Solid element background color
    modifier = Modifier.background(color = Color.Green)
)

與上述範例類似,您可以在版面配置中新增修飾符,利用排列和對齊屬性放置子項元素。

如要在 Row 內設定子項的位置,請設定 horizontalArrangementverticalAlignment 引數。如要針對 Column 進行這項設定,則應設定 verticalArrangementhorizontalAlignment 引數。

當版面配置的大小大於其子項總和時,排列屬性會用來排列子項元素。

舉例來說,如果 Column 的大小大於其子項大小的總和,您可以指定 verticalArrangement 來定義子項在 Column 中的位置。以下是各種垂直排列方式的插圖:

相同高度、物件之間間距、物件前後間距、均等間距、頂端、中間和底部

同樣地,當 Row 的大小大於子項大小的總和時,您可以指定 horizontalArrangement 來定義子項在 Row 中的位置。下圖呈現各種水平排列的方式:

相同粗細、物件之間間距、物件前後間距、均等間距、結尾、中間和開始

對齊屬性是用來讓子項元素對齊版面配置的起始、中央或結尾處。

6. 對齊及排列文字

在這項工作中,您要觀察在先前程式碼研究室中新增的程式碼,排列應用程式中的文字。

  1. MainActivity.kt 檔案中,捲動至 GreetingText() 函式。欄中的 verticalArrangement 屬性已設為 Arrangement.Center,因此畫面上的文字內容會置中顯示。
@Composable
fun GreetingText(message: String, from: String, modifier: Modifier = Modifier) {
    Column(
        verticalArrangement = Arrangement.Center,
        modifier = modifier
    ) {
        Text(
            text = message,
            fontSize = 100.sp,
            lineHeight = 116.sp,
            textAlign = TextAlign.Center
        )
        Text(
            text = from,
            fontSize = 36.sp,
            modifier = Modifier
                .padding(16.dp)
                .align(alignment = Alignment.End)
        )
    }
}

邊框間距

圍繞其內容的 UI 元素。如要避免元素邊緣與文字相距太近,可以在每一側指定「邊框間距」大小。

無邊框間距的 Text 可組合項

含邊框間距的 Text 可組合項

邊框間距可用做修飾符,也就是能套用至任何可組合函式。在可組合項的每一側,padding 修飾符會採用選用引數來定義邊框間距量。

圖表顯示頂部、起始、底部和結尾邊框間距

// This is an example.
Modifier.padding(
    start = 16.dp,
    top = 16.dp,
    end = 16.dp,
    bottom = 16.dp
)
  1. 換您上場囉!在 MainActivity.kt 檔案中,捲動至呼叫 GreetingText() 函式的位置,並留意邊框間距屬性。
modifier = Modifier
    .fillMaxSize()
    .padding(8.dp)
  1. 同樣地,留意在 GreetingText() 函式中,簽名 Text 可組合函式的邊框間距。
modifier = Modifier
    .padding(16.dp)
    .align(alignment = Alignment.End)

7. 採用完善的程式碼做法

翻譯

請特別注意,您在撰寫應用程式時,系統可能會將您的應用程式內容翻譯成其他語言。如同您於先前程式碼研究室所學,String 資料類型是一系列半形字元,例如 "Happy Birthday Sam!"

經過「硬式編碼」的字串會直接寫入應用程式的程式碼。這類字串會提高應用程式翻譯成其他語言的難度,並導致較不容易在應用程式的不同部分重複使用字串。如要解決這些問題,可以將字串擷取至資源檔案。請勿以硬式編碼的方式將字串寫入程式碼,而是將字串置於檔案中、為字串資源命名,然後在需要用到字串時使用這些名稱。即使字串有所變更或翻譯成其他語言,名稱仍會維持不變。

  1. MainActivity.kt 檔案中,捲動至 onCreate() 函式。選取生日祝福語「Happy Birthday Sam!」字串 (不加引號)。
  2. 按一下畫面左側的燈泡圖示。
  3. 選取「Extract string resource」。

eed032464b68ee5.png

Android Studio 會開啟「Extract Resource」對話方塊。在這個對話方塊中,您可以自訂字串資源的名稱,以及儲存方式的詳細資料。在「Resource name」欄位中,輸入字串要命名的名稱。「Resource value」欄位可讓您輸入實際字串本身。

  1. 在「Extract Resource」對話方塊中,將「Resource name」變更為 happy_birthday_text

字串資源應有小寫名稱,且每個字詞之間應用底線分開。其他設定保留預設值。

d6cb11f087b79f1e.png

  1. 按一下「OK」
  2. 留意程式碼的變更。

經過硬式編碼的字串現已替換為呼叫 getString() 函式。

GreetingImage(
    message = getString(R.string.happy_birthday_text),
    from = "From Emma",
    modifier = Modifier.padding(8.dp)
)
  1. 在「Project」窗格中,從 app > res > values > strings.xml 路徑開啟「string.xml」檔案,您會發現 Android Studio 已建立名為 happy_birthday_text 的字串資源。
<resources>
    <string name="app_name">Happy Birthday</string>
    <string name="happy_birthday_text">Happy Birthday Sam!</string>
</resources>

strings.xml 檔案含有使用者在應用程式中看到的字串清單。請注意,應用程式名稱也是字串資源。只要將所有字串集中在一起,就能更輕鬆地翻譯應用程式中的所有文字,並更輕鬆地在應用程式的不同部分重複使用字串。

  1. 請按照相同步驟擷取簽名 Text 可組合項,但此次請在「Resource name」欄位中輸入 signature_text

完成的檔案應如此程式碼片段所示:

<resources>
    <string name="app_name">Happy Birthday</string>
    <string name="happy_birthday_text">Happy Birthday Sam!</string>
    <string name="signature_text">From Emma</string>
</resources>
  1. 更新 BirthdayCardPreview(),使用 stringResource() 和擷取的字串。
@Preview(showBackground = true)
@Composable
fun BirthdayCardPreview() {
    HappyBirthdayTheme {
        GreetingImage(
            message = stringResource(R.string.happy_birthday_text),
            from = stringResource(R.string.signature_text)
        )
    }
}
  1. 再次執行應用程式,確認應用程式仍可正常運作。

8. 試試這項挑戰

太棒了!您在應用程式中加入了圖片,歡迎嘗試以下挑戰:

  1. 排列或對齊署名文字可組合函式,讓署名在畫面上置中對齊。

應用程式應如下所示:

b681900fe13e5598.png

以下是 GreetingText() 函式的解決方案程式碼,供您參考:

@Composable
fun GreetingText(message: String, from: String, modifier: Modifier = Modifier) {
    Column(
        verticalArrangement = Arrangement.Center,
        modifier = modifier
    ) {
        Text(
            text = message,
            fontSize = 100.sp,
            lineHeight = 116.sp,
            textAlign = TextAlign.Center
        )
        Text(
            text = from,
            fontSize = 36.sp,
            modifier = Modifier
                .padding(16.dp)
                .align(alignment = Alignment.CenterHorizontally)
        )
    }
}

9. 取得解決方案程式碼

Happy Birthday 應用程式的解決方案程式碼位於 GitHub。

GitHub 服務可讓開發人員管理軟體專案的程式碼。其使用 Git 版本管控系統,追蹤每個程式碼版本的變更。如果您曾檢視 Google 文件中的文件版本記錄,可以看到過去編輯的內容與編輯時間。同樣地,您可以追蹤專案中程式碼的版本記錄。以個別使用者或團隊身分進行專案時,這項功能非常實用。

GitHub 也提供可讓您檢視及管理專案的網站。透過這個 GitHub 連結,您可以在線上瀏覽 Happy Birthday 專案檔案,或將檔案下載下載至電腦。

完成程式碼研究室後,如要下載當中用到的程式碼,可以使用以下 Git 指令:

$ git clone https://github.com/google-developer-training/basic-android-kotlin-compose-birthday-card-app.git

另外,您也可以下載存放區為 ZIP 檔案,然後解壓縮並在 Android Studio 中開啟。

如要查看解決方案程式碼,請前往 GitHub

GitHub 中的分支版本

在瞭解分支版本之前,請先瞭解什麼是存放區。存放區是您複製在電腦上的完整專案 (目錄和檔案)。分支版本是存放區的版本,換言之,就是獨立的開發線。以本課程為例,「starter」分支版本是可在程式碼研究室中做為建構基礎的專案版本。mainsolutions 分支版本是程式碼研究室結束時的專案版本,包含完整的解決方案程式碼。

存放區可包含多個分支版本,這表示存放區中有多個程式碼版本。

10. 結語

您已在 Happy Birthday 應用程式中加入圖片、使用修飾符將文字對齊、遵循無障礙設計規範,並讓應用程式更容易翻譯成其他語言。更重要的是,您成功建構了自己的 Happy Birthday 應用程式!歡迎在社群媒體上分享作品,並加上 #AndroidBasics 主題標記,方便我們瀏覽。

摘要

  • 使用 Android Studio 中的「Resource Manager」分頁標籤,可協助您新增及管理圖片和其他資源。
  • Image 可組合項為可顯示應用程式中圖片的 UI 元素。
  • Image 可組合項應包含內容說明,讓使用者更容易使用您的應用程式。
  • 向使用者顯示的生日問候語等文字應擷取到字串資源中,方便將應用程式翻譯成其他語言。

瞭解詳情