MDC-102 Android: โครงสร้างและเลย์เอาต์วัสดุ (Kotlin)

โลโก้_components_color_2x_web_96dp.png

Material Components (MDC) ช่วยให้นักพัฒนาซอฟต์แวร์นํา Material Design ไปใช้ได้ MDC สร้างโดยทีมวิศวกรและนักออกแบบ UX ที่ Google มีคอมโพเนนต์ UI ที่สวยงามและใช้งานได้จํานวนมาก และพร้อมใช้งานสําหรับ Android, iOS, เว็บ และ Flitter

material.io/develop

ใน Codelab MDC-101 คุณใช้คอมโพเนนต์วัสดุ 2 อย่าง (MDC) เพื่อสร้างหน้าเข้าสู่ระบบ ได้แก่ ช่องข้อความและปุ่มที่มีระลอกหมึก ทีนี้เรามาขยายรากฐานนี้โดยเพิ่มการนําทาง โครงสร้าง และข้อมูลกัน

สิ่งที่คุณจะสร้าง

ใน Codelab นี้ คุณจะต้องสร้างหน้าจอหลักสําหรับแอปชื่อ Shrine ซึ่งเป็นแอปอีคอมเมิร์ซที่ขายเสื้อผ้าและของใช้ในบ้าน ซึ่งประกอบด้วย

  • แถบแอปด้านบน
  • รายการตารางกริดที่เต็มไปด้วยผลิตภัณฑ์

คอมโพเนนต์ MDC-Android ใน Codelab นี้

  • เลย์เอาต์แอป
  • มุมมอง Material Material

สิ่งที่ต้องมี

  • ความรู้เบื้องต้นเกี่ยวกับการพัฒนา Android
  • Android Studio (ดาวน์โหลดได้ที่นี่หากยังไม่มี)
  • โปรแกรมจําลองหรืออุปกรณ์ Android (พร้อมใช้งานผ่าน Android Studio)
  • โค้ดตัวอย่าง (ดูขั้นตอนถัดไป)

คุณจะให้คะแนนประสบการณ์ในการสร้างแอป Android ในระดับใด

มือใหม่ ปานกลาง เชี่ยวชาญ

การดําเนินการต่อจาก MDC-101

หากคุณกรอก MDC-101 เสร็จแล้ว คุณควรเตรียมโค้ดสําหรับ Codelab นี้ ข้ามไปขั้นตอนที่ 3: เพิ่มแถบแอปด้านบน

เริ่มต้นใหม่ทั้งหมด

ดาวน์โหลดแอป Starter Lab

ดาวน์โหลดแอปเริ่มต้น

แอปเริ่มต้นจะอยู่ในไดเรกทอรี material-components-android-codelabs-102-starter/kotlin ตรวจสอบว่าได้ cd ในไดเรกทอรีนั้นก่อนเริ่มต้น

...หรือโคลนจาก GitHub

หากต้องการโคลน Codelab นี้จาก GitHub ให้เรียกใช้คําสั่งต่อไปนี้

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

โหลดโค้ดเริ่มต้นใน Android Studio

  1. เมื่อวิซาร์ดการตั้งค่าเสร็จสิ้นและหน้าต่างยินดีต้อนรับสู่ Android Studio ปรากฏขึ้น ให้คลิกเปิดโครงการ Android Studio ที่มีอยู่ ไปที่ไดเรกทอรีที่ติดตั้งโค้ดตัวอย่าง แล้วเลือก kotlin ->ศาลเจ้า(หรือค้นหาศาลเจ้าในคอมพิวเตอร์ของคุณ) เพื่อเปิดโปรเจ็กต์การจัดส่ง
  2. รอสักครู่เพื่อให้ Android Studio สร้างและซิงค์โปรเจ็กต์ดังที่แสดงตามสัญญาณบอกสถานะกิจกรรมที่ด้านล่างของหน้าต่าง Android Studio
  3. เมื่อถึงจุดนี้ Android Studio อาจแสดงข้อผิดพลาดบิลด์บางรายการเนื่องจากคุณไม่มี Android SDK หรือเครื่องมือสร้าง เช่น ดังที่แสดงด้านล่าง ทําตามวิธีการใน Android Studio เพื่อติดตั้ง/อัปเดตและซิงค์โปรเจ็กต์

เพิ่มทรัพยากร Dependency ของโปรเจ็กต์

โครงการต้องพึ่งพาไลบรารีการสนับสนุนของ Android สําหรับ MDC โค้ดตัวอย่างที่คุณดาวน์โหลดควรมีรายการทรัพยากร Dependency นี้อยู่แล้ว แต่เราขอแนะนําให้ทําตามขั้นตอนต่อไปนี้เพื่อให้แน่ใจว่า

  1. ไปที่ไฟล์ build.gradle ของโมดูล app##39; และตรวจสอบว่าบล็อก dependencies มีทรัพยากร Dependency ใน MDC ของ Android ดังนี้
api 'com.google.android.material:material:1.1.0-alpha06'
  1. (ไม่บังคับ) หากจําเป็น ให้แก้ไขไฟล์ build.gradle เพื่อเพิ่มทรัพยากร Dependency ต่อไปนี้และซิงค์โปรเจ็กต์
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. ตรวจสอบว่าการกําหนดค่าบิวด์ทางด้านซ้ายของปุ่มเรียกใช้ / เล่น คือ app
  2. กดปุ่มเรียกใช้ / เล่นสีเขียวเพื่อสร้างและเรียกใช้แอป
  3. หากคุณมีอุปกรณ์ Android ที่แสดงอยู่ในอุปกรณ์ที่พร้อมใช้งานอยู่แล้ว ให้ข้ามไปที่ขั้นตอนที่ 8 ในหน้าต่างเลือกเป้าหมายการติดตั้งใช้งาน หรือคลิกสร้างอุปกรณ์เสมือนจริงใหม่
  4. ในหน้าจอเลือกฮาร์ดแวร์ ให้เลือกอุปกรณ์โทรศัพท์ เช่น Pixel 2 แล้วคลิกถัดไป
  5. ในหน้าจออิมเมจระบบ ให้เลือกเวอร์ชัน Android ล่าสุด ซึ่งควรเป็นระดับ API สูงสุด หากยังไม่มีการติดตั้ง ให้คลิกลิงก์ดาวน์โหลดที่ปรากฏและดาวน์โหลดให้เสร็จสมบูรณ์
  6. คลิกถัดไป
  7. ในหน้าจออุปกรณ์เสมือนจริงของ Android (AVD) ให้คงการตั้งค่าไว้ตามเดิม แล้วคลิกเสร็จสิ้น
  8. เลือกอุปกรณ์ Android จากกล่องโต้ตอบเป้าหมายของการทําให้ใช้งานได้
  9. คลิกตกลง
  10. Android Studio จะสร้างแอป ทําให้แอปใช้งานได้ และเปิดโดยอัตโนมัติในอุปกรณ์เป้าหมาย

สำเร็จ! คุณจะเห็นหน้าการเข้าสู่ระบบศาลเจ้าจาก Codelab ของ MDC-101

เมื่อหน้าจอเข้าสู่ระบบดูดีแล้ว ให้ป้อนข้อมูลแอปด้วยผลิตภัณฑ์บางอย่าง

หน้าจอหลักจะแสดงเมื่อมีการปิดหน้าเข้าสู่ระบบด้วยหน้าจอที่ระบุว่า "คุณทําได้!" เยี่ยมเลย! แต่ตอนนี้ผู้ใช้ของเราไม่มีการดําเนินการหรือดําเนินการใดๆ ในแอปแล้ว ก็ถึงเวลาเพิ่มการนําทาง

การออกแบบเนื้อหานําเสนอรูปแบบการนําทางที่ช่วยให้มั่นใจว่าจะมีความสามารถในการใช้งานสูง องค์ประกอบหนึ่งที่มองเห็นได้ชัดเจนที่สุดคือแถบแอปด้านบน

ในการนําทางและให้ผู้ใช้เข้าถึงการดําเนินการอื่นๆ ได้อย่างรวดเร็ว มาเพิ่มแถบแอปยอดนิยมกัน

เพิ่มวิดเจ็ต AppBar

ใน shr_product_grid_fragment.xml ให้ลบบล็อก <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 ให้เพิ่มสิ่งต่อไปนี้ลงในคอมโพเนนต์ XML Toolbar ที่คุณเพิ่งเพิ่มลงในเลย์เอาต์

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 ว่าปุ่มการทํางาน เราจะจัดรูปแบบแถบแอปด้านบนและเพิ่มปุ่มการทํางานลงในเมนูแบบเป็นโปรแกรม

ในฟังก์ชัน onCreateView ของ ProductGridFragment.kt&#39 ให้ตั้งค่า Toolbar ของ activity เพื่อใช้เป็น ActionBar โดยใช้ setSupportActionBar ซึ่งทําได้หลังจากสร้างข้อมูลพร็อพเพอร์ตี้ด้วย 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)
}

สุดท้าย ลบล้าง onCreate() ใน ProductGridFragment.kt และหลังจากเรียกใช้ super() ให้เรียกใช้ setHasOptionMenu ด้วย true

ProductGridFragment.kt

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

ข้อมูลโค้ดด้านบนได้ตั้งค่าแถบแอปจากเลย์เอาต์ XML เป็นแถบการทํางานสําหรับกิจกรรมนี้ โค้ดเรียกกลับ onCreateOptionsMenu จะบอกกิจกรรมที่จะใช้เป็นเมนูของเรา ในกรณีนี้ ก็จะนํารายการในเมนูจาก R.menu.shr_toolbar_menu ไปไว้ในแถบแอป ไฟล์เมนูประกอบด้วย 2 รายการ ได้แก่ "Search" และ "Filter"

เมนู shr_แถบเครื่องมือ_.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)
   }
}

สร้างและเรียกใช้ หน้าจอหลักควรมีลักษณะดังนี้

ตอนนี้แถบเครื่องมือจะมีไอคอนการนําทาง ชื่อ และไอคอนการทํางาน 2 ไอคอนอยู่ทางด้านขวา แถบเครื่องมือยังจะแสดงระดับความสูงโดยใช้เงาเล็กๆ ที่แสดงบนเลเยอร์ที่ต่างจากเลเยอร์ของเนื้อหา

ถึงตอนนี้ แอปของเรามีโครงสร้างบางอย่าง มาจัดระเบียบเนื้อหาด้วยการวางไว้ในการ์ดกัน

เพิ่มบัตร

มาเริ่มกันที่การเพิ่มการ์ด 1 ใบไว้ใต้แถบแอปด้านบน การ์ดควรมีภูมิภาคสําหรับรูปภาพ ชื่อ และป้ายกํากับสําหรับข้อความรอง เพิ่มสิ่งต่อไปนี้ใน shr_product_grid_fragment.xml ใต้ AppBarLayout

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>

สร้างและเรียกใช้

ในตัวอย่างนี้ คุณจะเห็นการ์ดอยู่ห่างจากขอบซ้ายและมีมุมโค้งมนและเงา (ซึ่งแสดงความสูงของการ์ด) องค์ประกอบทั้งหมดเรียกว่า "container." นอกจากคอนเทนเนอร์แล้ว คุณยังเลือกองค์ประกอบทั้งหมดภายในคอนเทนเนอร์ได้อีกด้วย

คุณเพิ่มองค์ประกอบต่อไปนี้ในคอนเทนเนอร์ได้ ไม่ว่าจะเป็นข้อความส่วนหัว ภาพขนาดย่อหรือรูปโปรไฟล์ ข้อความส่วนหัวย่อย เส้นแบ่ง รวมถึงปุ่มและไอคอน เช่น การ์ดที่เพิ่งสร้างขึ้นมี TextView อยู่ 2 รายการ (อย่างหนึ่งคือชื่อ และอีกรายการหนึ่งเป็นข้อความรอง) ใน LinearLayout ซึ่งสอดคล้องกับด้านล่างของการ์ด

ปกติแล้วการ์ดจะแสดงในคอลเล็กชันที่มีการ์ดอื่นๆ ในส่วนถัดไปของ Codelab นี้ เราจะจัดคอลเล็กชันดังกล่าวเป็นตารางกริดในตารางกริด

เมื่อมีการ์ดหลายใบแสดงในหน้าจอ การ์ดเหล่านั้นจะรวมกันเป็นคอลเล็กชันอย่างน้อย 1 คอลเล็กชัน การ์ดในตารางกริดเป็นระนาบเดียวกัน ซึ่งหมายความว่าใช้ระดับระดับความสูงขณะพักเดียวกันกับกันและกัน (เว้นแต่จะหยิบหรือลากไป แต่เราจะไม่พูดถึงใน Codelab นี้)

ตั้งค่าตารางกริดของการ์ด

ดูไฟล์ 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 ซึ่งช่วยให้เราโหลดและแสดงรูปภาพจาก URL ได้) และ TextViews 2 รายการ

ถัดไปดูที่ 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)

ในการตั้งค่าตารางกริด เราจะนําตัวยึดตําแหน่ง MaterialCardView ออกจาก shr_product_grid_fragment.xml ก่อน จากนั้น คุณควรเพิ่มคอมโพเนนต์ที่แสดงตารางของการ์ด ในกรณีนี้ เราจะใช้ RecyclerView เพิ่มคอมโพเนนต์ RecyclerView ลงใน shr_product_grid_fragment.xml ด้านล่างคอมโพเนนต์ XML AppBarLayout

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() ให้เพิ่มโค้ดการเริ่มต้นของ RecyclerView ลงใน ProductGridFragment.kt หลังจากเรียกใช้ setUpToolbar(view) และก่อนคําสั่ง return

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&#39, การเริ่มต้นใช้งาน และการตั้งค่าอะแดปเตอร์ RecyclerView&#39

ตอนนี้ไฟล์ 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)
   }
}

สร้างและเรียกใช้

การ์ดมาแล้ว พวกเขายังไม่แสดงอะไรเลย มาเพิ่มข้อมูลผลิตภัณฑ์กัน

เพิ่มรูปภาพและข้อความ

เพิ่มรูปภาพ ชื่อผลิตภัณฑ์ และราคาสําหรับแต่ละการ์ด นามธรรม ViewHolder ของเราจะเก็บรักษายอดดูของการ์ดแต่ละใบ ใน ViewHolder ให้เพิ่มข้อมูลพร็อพเพอร์ตี้ 3 รายการดังนี้

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

อัปเดตเมธอด onBindViewHolder() ใน ProductCardRecyclerViewAdapter เพื่อตั้งชื่อ ราคา และรูปภาพผลิตภัณฑ์สําหรับแต่ละมุมมองผลิตภัณฑ์ดังที่แสดงด้านล่าง

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

ในหน้านี้มีการตั้งค่าข้อมูลข้อความในแต่ละ TextView ของ ViewHolder และเรียก ImageRequester เพื่อรับรูปภาพจาก URL ImageRequester คือชั้นเรียนที่เราจัดให้ไว้เพื่อความสะดวกของคุณ และใช้ไลบรารี Volley (เป็นหัวข้อที่ไม่อยู่ในขอบเขตของ Codelab นี้ แต่คุณสามารถสํารวจโค้ดด้วยตนเองได้)

สร้างและเรียกใช้

ผลิตภัณฑ์ของเราจะปรากฏในแอปแล้ว

แอปของเรามีขั้นตอนพื้นฐานที่นําผู้ใช้ไปยังหน้าจอการเข้าสู่ระบบไปยังหน้าจอหลัก ซึ่งคุณจะดูผลิตภัณฑ์ได้ เพียงใส่โค้ดแอปเพียง 2-3 บรรทัด เราได้เพิ่มแถบแอปยอดนิยมพร้อมด้วยชื่อและปุ่ม 3 ปุ่ม รวมถึงตารางของการ์ดเพื่อนําเสนอเนื้อหาของแอป ตอนนี้หน้าจอหลักของเราใช้งานง่ายและเรียบง่าย มีโครงสร้างพื้นฐานและเนื้อหาที่นําไปใช้ได้จริง

ขั้นตอนถัดไป

ตอนนี้ด้วยแถบแอป การ์ด ช่องข้อความ และปุ่มด้านบน ตอนนี้เราได้ใช้องค์ประกอบหลัก 4 อย่างของ Material Design จากไลบรารี MDC-Android คุณสํารวจคอมโพเนนต์เพิ่มเติมได้โดยไปที่แคตตาล็อก MDC-Android

แม้ว่าแอปจะทํางานได้อย่างสมบูรณ์ แต่แอปของเรายังไม่รองรับการแสดงยี่ห้อหรือสไตล์ ใน MDC-103: ธีม Material Design ด้วยสี รูปร่าง ความสูง และประเภท เราจะปรับแต่งสไตล์ของคอมโพเนนต์เหล่านี้เพื่อสื่อถึงแบรนด์ที่มีความทันสมัยและมีชีวิตชีวา

ฉันเรียน Codelab นี้ให้เสร็จได้ด้วยเวลาและความพยายามที่สมเหตุสมผล

เห็นด้วยอย่างยิ่ง เห็นด้วย เฉยๆ ไม่เห็นด้วย ไม่เห็นด้วยอย่างยิ่ง

ฉันต้องการใช้คอมโพเนนต์วัสดุต่อไปในอนาคต

เห็นด้วยอย่างยิ่ง เห็นด้วย เฉยๆ ไม่เห็นด้วย ไม่เห็นด้วยอย่างยิ่ง