MDC-102 Android:Material Design 結構和版面配置 (Kotlin)

1. 簡介

logo_components_color_2x_web_96dp.png

Material Design 元件 (MDC) 可協助開發人員實作質感設計。MDC 是由 Google 的工程師和使用者體驗設計師團隊所開發,提供數十種美觀實用的 UI 元件,適用於 Android、iOS、網頁和 Flutter。material.io/develop

在程式碼研究室 MDC-101 中,您使用兩個 Material 元件 (MDC) 建構登入頁面:文字欄位和含有墨水漣漪的按鈕。接下來,我們將在這個基礎上加入導覽、結構和資料。

建構項目

在本程式碼研究室中,您會為名為 Shrine 的電子商務應用程式建構主畫面,這是一款用於販售服飾和居家用品的電子商務應用程式。其中包含:

  • 頂端應用程式列
  • 包含大量產品的格狀清單

249db074eff043f4.png

本程式碼研究室中的 MDC-Android 元件

  • AppBarLayout
  • MaterialCardView

軟硬體需求

  • 具備 Android 開發作業的基本知識
  • Android Studio (如果尚未安裝,請按這裡下載)
  • Android 模擬器或裝置 (可透過 Android Studio 取得)
  • 程式碼範例 (請參閱下一個步驟)

你對建立 Android 應用程式的經驗程度為何?

新手 中級 熟練

2. 設定開發環境

是否要從 MDC-101 課程繼續學習?

如果您已完成 MDC-101 課程,您的程式碼應已準備好用於本程式碼研究室。跳至步驟 3:新增頂端應用程式列

從頭開始?

下載程式碼研究室入門應用程式

範例應用程式位於 material-components-android-codelabs-102-starter/kotlin 目錄中。請務必先 cd 進入該目錄,再開始操作。

...或從 GitHub 複製

如要從 GitHub 複製本程式碼研究室,請執行下列指令:

git clone https://github.com/material-components/material-components-android-codelabs
cd material-components-android-codelabs/
git checkout 102-starter

在 Android Studio 中載入範例程式碼

  1. 設定精靈完成後,系統會顯示「Welcome to Android Studio」視窗,請按一下「Open an existing Android Studio project」。前往安裝範例程式碼的目錄,然後依序選取「kotlin」>「shrine」(或在電腦上搜尋「shrine」),開啟 Shipping 專案。
  2. 請稍候,讓 Android Studio 建構及同步處理專案,Android Studio 視窗底部的活動指標會顯示這項作業的進度。
  3. 此時,Android Studio 可能會引發部分建構錯誤,因為缺少 Android SDK 或建構工具 (如下所示)。請按照 Android Studio 中的操作說明安裝/更新這些項目,並同步處理專案。

KzoYWC1S7Se7yL8igi1vXF_mbVxAdl2lg5kb7RODrsVpEng0G6U3NK1Qnn0faBBZd2u71yMXioy9tD-7fv3NXvVO4N3EtMMeWDTmqBMMl6egd9R5uXX0T_SKmahbmRor3wZZHX0ByA

新增專案依附元件

專案需要依附 MDC Android 支援程式庫。您下載的範例程式碼應已列出此依附元件,但建議您執行下列步驟,以確保依附元件已正確列出。

  1. 前往 app 模組的 build.gradle 檔案,確認 dependencies 區塊包含 MDC Android 的依附元件:
api 'com.google.android.material:material:1.1.0-alpha06'
  1. (選用) 視需要編輯 build.gradle 檔案,新增下列依附元件並同步處理專案。
dependencies {
    api 'com.google.android.material:material:1.1.0-alpha06'
    implementation 'androidx.legacy:legacy-support-v4:1.0.0'
    implementation 'com.android.volley:volley:1.1.1'
    implementation 'com.google.code.gson:gson:2.8.5'
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.21"
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test:core:1.1.0'
    androidTestImplementation 'androidx.test.ext:junit:1.1.0'
    androidTestImplementation 'androidx.test:runner:1.2.0-alpha05'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0-alpha05'
}

執行範例應用程式

  1. 請確認「Run」/「Play」按鈕左側的建構設定為 app
  2. 按下綠色的「Run」/「Play」按鈕,即可建構並執行應用程式。
  3. 如果「Select Deployment Target」視窗中已列出 Android 裝置,請直接跳至步驟 8。否則,請按一下「Create New Virtual Device」
  4. 在「選取硬體」畫面中選取手機裝置 (例如「Pixel 2」),然後點選「下一步」
  5. 在「System Image」畫面中選取最新的 Android 版本 (最好是最高 API 級別)。如果尚未安裝,請按一下畫面中顯示的「Download」(下載) 連結並完成下載。
  6. 點選「下一步」
  7. 在「Android Virtual Device (AVD)」(Android 虛擬裝置 (AVD)) 畫面上維持原設定,然後按一下「Finish」(完成)
  8. 從部署目標對話方塊中選取「Android 裝置」
  9. 按一下 [確定]。
  10. Android Studio 會建構及部署應用程式,並自動在目標裝置上開啟應用程式。

大功告成!您應該會看到 MDC-101 程式碼研究室中的 Shrine 登入頁面。

4cb0c218948144b4.png

登入畫面顯示正常後,我們來為應用程式填入一些產品。

3. 新增頂端應用程式列

登入頁面關閉後,系統會顯示主畫面,並顯示「You did it!」(您已完成) 的畫面。太好了!不過,使用者現在無法採取任何行動,也不知道自己在應用程式中的位置。為了解決這個問題,我們要新增導覽功能。

Material Design 提供的瀏覽模式可確保高度可用性。其中最明顯的元件之一是頂端應用程式列。

為了提供導覽功能,讓使用者快速存取其他動作,我們來新增頂端應用程式列。

新增 AppBar 小工具

shr_product_grid_fragment.xml 中,刪除包含「You did it!」的 <LinearLayout> 區塊。TextView 並替換為以下內容:

shr_product_grid_fragment.xml

<com.google.android.material.appbar.AppBarLayout
   android:layout_width="match_parent"
   android:layout_height="wrap_content">

   <androidx.appcompat.widget.Toolbar
       android:id="@+id/app_bar"
       style="@style/Widget.Shrine.Toolbar"
       android:layout_width="match_parent"
       android:layout_height="?attr/actionBarSize"
       app:title="@string/shr_app_name" />
</com.google.android.material.appbar.AppBarLayout>

shr_product_grid_fragment.xml 現在應如下所示:

shr_product_grid_fragment.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:app="http://schemas.android.com/apk/res-auto"
   xmlns:tools="http://schemas.android.com/tools"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   tools:context=".ProductGridFragment">

   <com.google.android.material.appbar.AppBarLayout
       android:layout_width="match_parent"
       android:layout_height="wrap_content">

       <androidx.appcompat.widget.Toolbar
           android:id="@+id/app_bar"
           style="@style/Widget.Shrine.Toolbar"
           android:layout_width="match_parent"
           android:layout_height="?attr/actionBarSize"
           app:title="@string/shr_app_name" />
   </com.google.android.material.appbar.AppBarLayout>
  
</FrameLayout>

許多應用程式列的標題旁都有按鈕。我們來在我們的應用程式中加入選單圖示。

新增導覽圖示

shr_product_grid_fragment.xml 中,將以下內容新增至剛新增至版面配置的 Toolbar XML 元件:

shr_product_grid_fragment.xml

app:navigationIcon="@drawable/shr_menu"

shr_product_grid_fragment.xml 應如下所示:

shr_product_grid_fragment.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:app="http://schemas.android.com/apk/res-auto"
   xmlns:tools="http://schemas.android.com/tools"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   tools:context=".ProductGridFragment">
  
   <com.google.android.material.appbar.AppBarLayout
       android:layout_width="match_parent"
       android:layout_height="wrap_content">

       <androidx.appcompat.widget.Toolbar
           android:id="@+id/app_bar"
           style="@style/Widget.Shrine.Toolbar"
           android:layout_width="match_parent"
           android:layout_height="?attr/actionBarSize"
           app:navigationIcon="@drawable/shr_menu"
           app:title="@string/shr_app_name" />
   </com.google.android.material.appbar.AppBarLayout>
  
</FrameLayout>

新增動作按鈕並設定頂端應用程式列的樣式

您也可以在應用程式列的末端新增按鈕。在 Android 中,這些按鈕稱為動作按鈕。我們將為頂端應用程式列設定樣式,並以程式輔助方式將動作按鈕新增至選單。

ProductGridFragment.ktonCreateView 函式中,使用 setSupportActionBaractivityToolbar 設為 ActionBar。使用 inflater 建立檢視區塊後,即可執行此操作。

ProductGridFragment.kt

override fun onCreateView(
       inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
   // Inflate the layout for this fragment with the ProductGrid theme
   val view = inflater.inflate(R.layout.shr_product_grid_fragment, container, false)

   // Set up the toolbar.
   (activity as AppCompatActivity).setSupportActionBar(view.app_bar)

   return view;
}

接著,我們直接在剛才用來設定工具列的方法下方,覆寫 onCreateOptionsMenu,將 shr_toolbar_menu.xml 的內容填充至工具列:

ProductGridFragment.kt

override fun onCreateOptionsMenu(menu: Menu, menuInflater: MenuInflater) {
   menuInflater.inflate(R.menu.shr_toolbar_menu, menu)
   super.onCreateOptionsMenu(menu, menuInflater)
}

最後,覆寫 ProductGridFragment.kt 中的 onCreate(),並在呼叫 super() 後使用 true 呼叫 setHasOptionMenu

ProductGridFragment.kt

override fun onCreate(savedInstanceState: Bundle?) {
   super.onCreate(savedInstanceState)
   setHasOptionsMenu(true)
}

上述程式碼片段會將 XML 版面配置的應用程式列設為此活動的動作列。回呼 onCreateOptionsMenu 會告訴活動要使用哪個選單。在這種情況下,它會將 R.menu.shr_toolbar_menu 的選單項目放入應用程式列。選單檔案包含兩個項目:「搜尋」和「篩選」。

shr_toolbar_menu.xml

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:app="http://schemas.android.com/apk/res-auto">
   <item
       android:id="@+id/search"
       android:icon="@drawable/shr_search"
       android:title="@string/shr_search_title"
       app:showAsAction="always" />
   <item
       android:id="@+id/filter"
       android:icon="@drawable/shr_filter"
       android:title="@string/shr_filter_title"
       app:showAsAction="always" />
</menu>

變更完成後,ProductGridFragment.kt 檔案應如下所示:

ProductGridFragment.kt

package com.google.codelabs.mdc.kotlin.shrine

import android.os.Bundle
import android.view.LayoutInflater
import android.view.Menu
import android.view.MenuInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.GridLayoutManager
import com.google.codelabs.mdc.kotlin.shrine.network.ProductEntry
import kotlinx.android.synthetic.main.shr_product_grid_fragment.view.*

class ProductGridFragment : Fragment() {

   override fun onCreate(savedInstanceState: Bundle?) {
       super.onCreate(savedInstanceState)
       setHasOptionsMenu(true)
   }

   override fun onCreateView(
           inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
       // Inflate the layout for this fragment with the ProductGrid theme
       val view = inflater.inflate(R.layout.shr_product_grid_fragment, container, false)

       // Set up the tool bar
       (activity as AppCompatActivity).setSupportActionBar(view.app_bar)

       return view;
   }

   override fun onCreateOptionsMenu(menu: Menu, menuInflater: MenuInflater) {
       menuInflater.inflate(R.menu.shr_toolbar_menu, menu)
       super.onCreateOptionsMenu(menu, menuInflater)
   }
}

建構及執行。你的主畫面應如下所示:

d04e8aa3b27f4754.png

工具列現在包含導覽圖示、標題,以及右側的兩個動作圖示。工具列也會使用細微的陰影顯示高度,讓它看起來與內容位於不同圖層。

4. 新增卡片

應用程式有了一些結構後,我們將內容放入資訊卡,以便進行整理。

新增卡片

讓我們先在頂端應用程式列下方新增一張資訊卡。資訊卡應包含圖片、標題和次要文字標籤區域。在 AppBarLayout 下方的 shr_product_grid_fragment.xml 中新增以下內容。

shr_product_grid_fragment.xml

<com.google.android.material.card.MaterialCardView
   android:layout_width="160dp"
   android:layout_height="180dp"
   android:layout_marginBottom="16dp"
   android:layout_marginLeft="16dp"
   android:layout_marginRight="16dp"
   android:layout_marginTop="70dp"
   app:cardBackgroundColor="?attr/colorPrimaryDark"
   app:cardCornerRadius="4dp">

   <LinearLayout
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:layout_gravity="bottom"
       android:background="#FFFFFF"
       android:orientation="vertical"
       android:padding="8dp">

       <TextView
           android:layout_width="match_parent"
           android:layout_height="wrap_content"
           android:padding="2dp"
           android:text="@string/shr_product_title"
           android:textAppearance="?attr/textAppearanceHeadline6" />

       <TextView
           android:layout_width="match_parent"
           android:layout_height="wrap_content"
           android:padding="2dp"
           android:text="@string/shr_product_description"
           android:textAppearance="?attr/textAppearanceBody2" />
   </LinearLayout>
</com.google.android.material.card.MaterialCardView>

建構並執行:

f6184a55ccb5f920.png

在這個預覽畫面中,您可以看到資訊卡從左側邊緣內縮,且具有圓角和陰影 (表示資訊卡的高度)。整個元素稱為「容器」。除了容器之外,容器中的所有元素皆為選用項目。

您可以在容器中加入下列元素:標題文字、縮圖或顯示圖片、子標題文字、分隔線,甚至是按鈕和圖示。舉例來說,我們剛建立的資訊卡在 LinearLayout 中包含兩個 TextView (一個用於標題,另一個用於次要文字),並與資訊卡底部對齊。

資訊卡通常會與其他資訊卡一起顯示。在本程式碼研究室的下一節中,我們會將這些項目以集合的形式在格線中排版。

5. 建立卡片格狀

如果畫面中有多張資訊卡,系統會將這些資訊卡分組成一個或多個集合。格狀卡片是共平面,也就是說,它們會共用相同的靜止高度 (除非選取或拖曳,但我們不會在本程式碼研究室中介紹這項操作)。

設定資訊卡格線

請查看我們提供的 shr_product_card.xml 檔案:

shr_product_card.xml

<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:app="http://schemas.android.com/apk/res-auto"
   android:layout_width="match_parent"
   android:layout_height="wrap_content"
   app:cardBackgroundColor="@android:color/white"
   app:cardElevation="2dp"
   app:cardPreventCornerOverlap="true">

   <LinearLayout
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:orientation="vertical">

       <com.android.volley.toolbox.NetworkImageView
           android:id="@+id/product_image"
           android:layout_width="match_parent"
           android:layout_height="@dimen/shr_product_card_image_height"
           android:background="?attr/colorPrimaryDark"
           android:scaleType="centerCrop" />

       <LinearLayout
           android:layout_width="match_parent"
           android:layout_height="wrap_content"
           android:orientation="vertical"
           android:padding="16dp">

           <TextView
               android:id="@+id/product_title"
               android:layout_width="match_parent"
               android:layout_height="wrap_content"
               android:text="@string/shr_product_title"
               android:textAppearance="?attr/textAppearanceHeadline6" />

           <TextView
               android:id="@+id/product_price"
               android:layout_width="match_parent"
               android:layout_height="wrap_content"
               android:text="@string/shr_product_description"
               android:textAppearance="?attr/textAppearanceBody2" />
       </LinearLayout>
   </LinearLayout>
</com.google.android.material.card.MaterialCardView>

這個資訊卡版面配置包含一個含有圖片的資訊卡 (在本例中為 NetworkImageView,可讓我們載入並顯示來自網址的圖片),以及兩個 TextViews

接著,請查看我們提供的 ProductCardRecyclerViewAdapter。這個套件與 ProductGridFragment 位於同一個套件中。

ProductCardRecyclerViewAdapter.kt

package com.google.codelabs.mdc.kotlin.shrine

import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView

import com.google.codelabs.mdc.kotlin.shrine.network.ProductEntry

/**
* Adapter used to show a simple grid of products.
*/
class ProductCardRecyclerViewAdapter(private val productList: List<ProductEntry>) : RecyclerView.Adapter<ProductCardViewHolder>() {

   override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ProductCardViewHolder {
       val layoutView = LayoutInflater.from(parent.context).inflate(R.layout.shr_product_card, parent, false)
       return ProductCardViewHolder(layoutView)
   }

   override fun onBindViewHolder(holder: ProductCardViewHolder, position: Int) {
       // TODO: Put ViewHolder binding code here in MDC-102
   }

   override fun getItemCount(): Int {
       return productList.size
   }
}

上方的轉接程式類別會管理格線的內容。為了判斷每個檢視畫面應如何處理指定內容,我們很快就會為 onBindViewHolder() 編寫程式碼。

您也可以在同一個套件中查看 ProductCardViewHolder。這個類別會儲存會影響資訊卡版面配置的檢視畫面,以便我們稍後修改這些檢視畫面。

ProductCardViewHolder.kt

package com.google.codelabs.mdc.kotlin.shrine

import android.view.View
import androidx.recyclerview.widget.RecyclerView

class ProductCardViewHolder(itemView: View) //TODO: Find and store views from itemView
   : RecyclerView.ViewHolder(itemView)

如要設定格線,請先從 shr_product_grid_fragment.xml 中移除預留位置 MaterialCardView。接下來,您應該新增代表資訊卡方格的元件。在本例中,我們會使用 RecyclerView。將 RecyclerView 元件新增至 AppBarLayout XML 元件下方的 shr_product_grid_fragment.xml

shr_product_grid_fragment.xml

<androidx.core.widget.NestedScrollView
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   android:layout_marginTop="56dp"
   android:background="@color/productGridBackgroundColor"
   android:paddingStart="@dimen/shr_product_grid_spacing"
   android:paddingEnd="@dimen/shr_product_grid_spacing"
   app:layout_behavior="@string/appbar_scrolling_view_behavior">

   <androidx.recyclerview.widget.RecyclerView
       android:id="@+id/recycler_view"
       android:layout_width="match_parent"
       android:layout_height="match_parent" />

</androidx.core.widget.NestedScrollView>

shr_product_grid_fragment.xml 應如下所示:

shr_product_grid_fragment.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:app="http://schemas.android.com/apk/res-auto"
   xmlns:tools="http://schemas.android.com/tools"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   tools:context=".ProductGridFragment">

   <com.google.android.material.appbar.AppBarLayout
       android:layout_width="match_parent"
       android:layout_height="wrap_content">

       <androidx.appcompat.widget.Toolbar
           android:id="@+id/app_bar"
           style="@style/Widget.Shrine.Toolbar"
           android:layout_width="match_parent"
           android:layout_height="?attr/actionBarSize"
           app:navigationIcon="@drawable/shr_menu"
           app:title="@string/shr_app_name" />
   </com.google.android.material.appbar.AppBarLayout>

   <androidx.core.widget.NestedScrollView
       android:layout_width="match_parent"
       android:layout_height="match_parent"
       android:layout_marginTop="56dp"
       android:background="@color/productGridBackgroundColor"
       android:paddingStart="@dimen/shr_product_grid_spacing"
       android:paddingEnd="@dimen/shr_product_grid_spacing"
       app:layout_behavior="@string/appbar_scrolling_view_behavior">

       <androidx.recyclerview.widget.RecyclerView
           android:id="@+id/recycler_view"
           android:layout_width="match_parent"
           android:layout_height="match_parent" />

   </androidx.core.widget.NestedScrollView>

</FrameLayout>

最後,在 onCreateView() 中,於呼叫 setUpToolbar(view) 後和 return 陳述式前方,將 RecyclerView 初始化程式碼加到 ProductGridFragment.kt 中:

ProductGridFragment.kt

override fun onCreateView(
       inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
   // Inflate the layout for this fragment with the ProductGrid theme
   val view = inflater.inflate(R.layout.shr_product_grid_fragment, container, false)

   // Set up the toolbar.
   (activity as AppCompatActivity).setSupportActionBar(view.app_bar)

   // Set up the RecyclerView
   view.recycler_view.setHasFixedSize(true)
   view.recycler_view.layoutManager = GridLayoutManager(context, 2, RecyclerView.VERTICAL, false)
   val adapter = ProductCardRecyclerViewAdapter(
           ProductEntry.initProductEntryList(resources))
   view.recycler_view.adapter = adapter
   val largePadding = resources.getDimensionPixelSize(R.dimen.shr_product_grid_spacing)
   val smallPadding = resources.getDimensionPixelSize(R.dimen.shr_product_grid_spacing_small)
   view.recycler_view.addItemDecoration(ProductGridItemDecoration(largePadding, smallPadding))

   return view;
}

上述程式碼片段包含設定 RecyclerView 所需的初始化步驟。包括設定 RecyclerView 的版面配置管理工具,以及初始化及設定 RecyclerView 的轉接器。

您的 ProductGridFragment.kt 檔案現在應如下所示:

ProductGridFragment .kt

package com.google.codelabs.mdc.kotlin.shrine

import android.os.Bundle
import android.view.LayoutInflater
import android.view.Menu
import android.view.MenuInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.google.codelabs.mdc.kotlin.shrine.network.ProductEntry
import kotlinx.android.synthetic.main.shr_product_grid_fragment.view.*

class ProductGridFragment : Fragment() {

   override fun onCreate(savedInstanceState: Bundle?) {
       super.onCreate(savedInstanceState)
       setHasOptionsMenu(true)
   }

   override fun onCreateView(
           inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
       // Inflate the layout for this fragment with the ProductGrid theme
       val view = inflater.inflate(R.layout.shr_product_grid_fragment, container, false)

       // Set up the toolbar.
       (activity as AppCompatActivity).setSupportActionBar(view.app_bar)

       // Set up the RecyclerView
       view.recycler_view.setHasFixedSize(true)
       view.recycler_view.layoutManager = GridLayoutManager(context, 2, RecyclerView.VERTICAL, false)
       val adapter = ProductCardRecyclerViewAdapter(
               ProductEntry.initProductEntryList(resources))
       view.recycler_view.adapter = adapter
       val largePadding = resources.getDimensionPixelSize(R.dimen.shr_product_grid_spacing)
       val smallPadding = resources.getDimensionPixelSize(R.dimen.shr_product_grid_spacing_small)
       view.recycler_view.addItemDecoration(ProductGridItemDecoration(largePadding, smallPadding))

       return view;
   }

   override fun onCreateOptionsMenu(menu: Menu, menuInflater: MenuInflater) {
       menuInflater.inflate(R.menu.shr_toolbar_menu, menu)
       super.onCreateOptionsMenu(menu, menuInflater)
   }
}

建構並執行:

f9aeab846fc3bb4c.png

卡片現在已經出爐了!目前還無法顯示任何內容,所以讓我們加入一些產品資料。

新增圖片和文字

為每張資訊卡新增圖片、產品名稱和價格。我們的 ViewHolder 抽象類別會保留每張資訊卡的檢視畫面。在 ViewHolder 中,新增三個檢視畫面,如下所示。

ProductCardViewHolder.kt

package com.google.codelabs.mdc.kotlin.shrine

import android.view.View
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView

import com.android.volley.toolbox.NetworkImageView

class ProductCardViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {

   var productImage: NetworkImageView = itemView.findViewById(R.id.product_image)
   var productTitle: TextView = itemView.findViewById(R.id.product_title)
   var productPrice: TextView = itemView.findViewById(R.id.product_price)
}

更新 ProductCardRecyclerViewAdapter 中的 onBindViewHolder() 方法,為每個產品檢視畫面設定標題、價格和產品圖片,如下所示:

ProductCardRecyclerViewAdapter.kt

override fun onBindViewHolder(holder: ProductCardViewHolder, position: Int) {
   if (position < productList.size) {
       val product = productList[position]
       holder.productTitle.text = product.title
       holder.productPrice.text = product.price
       ImageRequester.setImageFromUrl(holder.productImage, product.url)
   }
}

上述程式碼會指示 RecyclerView 的轉接器使用 ViewHolder 處理每張卡片的操作。

這裡會設定 ViewHolder 的每個 TextView 上的文字資料,並呼叫 ImageRequester 從網址取得圖片。為了方便起見,我們提供了 ImageRequester 這個類別,並使用 Volley 程式庫 (這是本程式碼研究室不在範圍內的主題,但您可以自行探索程式碼)。

建構並執行:

249db074eff043f4.png

我們的產品現在已顯示在應用程式中!

6. 重點回顧

我們的應用程式具有基本流程,可將使用者從登入畫面帶往可查看產品的主畫面。我們只需加入幾行程式碼,就能新增頂端應用程式列 (含標題和三個按鈕),以及資訊卡格狀陣列,用於呈現應用程式內容。我們的首頁現在簡單實用,具備基本結構和可執行內容。

後續步驟

您現在可以透過頂端應用程式列、資訊卡、文字欄位和按鈕,使用 MDC-Android 程式庫的四個核心 Material Design 元件!如要探索更多元件,請造訪 MDC-Android Catalog。

雖然可以完整運作,但應用程式無法呈現任何特定的品牌或風格。在 MDC-103:利用顏色、形狀、高度和類型建立 Material Design 主題 中,我們將自訂這些元件的樣式,以呈現鮮明、現代的品牌形象。

我可以在合理的時間內,完成本程式碼研究室

非常同意 同意 中立 不同意 非常不同意

我想日後繼續使用 Material Design 元件

非常同意 同意 無意見 不同意 非常不同意