1. บทนำ
| Material Components (MDC) ช่วยให้นักพัฒนานำดีไซน์ Material มาใช้ MDC สร้างโดยทีมวิศวกรและนักออกแบบ UX ที่ Google โดยมีคอมโพเนนต์ UI ที่สวยงามและใช้งานได้หลายสิบอย่างและพร้อมใช้งานสำหรับ Android, iOS, เว็บ และ Flutter.material.io/develop | 
ใน Codelab MDC-101 คุณใช้ Material Components (MDC) 2 รายการเพื่อสร้างหน้าเข้าสู่ระบบ ซึ่งได้แก่ ช่องข้อความและปุ่ม ทีนี้เราจะมาต่อยอดจากรากฐานนี้ด้วยการเพิ่มการนำทาง โครงสร้าง และข้อมูล
สิ่งที่คุณจะสร้าง
ใน Codelab นี้ คุณจะได้สร้างหน้าจอหลักสำหรับแอปชื่อ Shrine ซึ่งเป็นแอปอีคอมเมิร์ซที่ขายเสื้อผ้าและของใช้ในบ้าน โดยจะประกอบด้วยข้อมูลต่อไปนี้
- แถบแอปด้านบน
- รายการผลิตภัณฑ์แบบตารางกริด

MDC-Android ใน Codelab นี้
- AppBarLayout
- MaterialCardView
สิ่งที่คุณต้องมี
- ความรู้พื้นฐานเกี่ยวกับการพัฒนา Android
- Android Studio (ดาวน์โหลดได้ที่นี่หากยังไม่มี)
- โปรแกรมจำลองหรืออุปกรณ์ Android (ใช้งานได้ผ่าน Android Studio)
- โค้ดตัวอย่าง (ดูขั้นตอนถัดไป)
คุณจะให้คะแนนประสบการณ์ในการสร้างแอป Android ของคุณในระดับใด
2. ตั้งค่าสภาพแวดล้อมในการพัฒนาซอฟต์แวร์
ต้องทำต่อจาก MDC-101 ใช่ไหม
หากคุณดำเนินการ MDC-101 เสร็จสมบูรณ์แล้ว โค้ดของคุณก็จะพร้อมใช้งานสำหรับ Codelab นี้ คุณอาจข้ามไปยังขั้นตอนที่ 3 เพิ่มแถบแอปด้านบนได้เลย
ต้องเริ่มใหม่ตั้งแต่ต้นใช่ไหม
ดาวน์โหลดแอป Codelab เริ่มต้น
แอปเริ่มต้นอยู่ในไดเรกทอรี material-components-android-codelabs-102-starter/java อย่าลืม 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
- เมื่อวิซาร์ดการตั้งค่าดำเนินการเสร็จแล้วและหน้าต่างยินดีต้อนรับสู่ Android Studio ปรากฏขึ้น ให้คลิกเปิดโปรเจ็กต์ Android Studio ที่มีอยู่ ไปที่ไดเรกทอรีที่คุณได้ติดตั้งโค้ดตัวอย่างไว้แล้ว และเลือก java -> ศาลเจ้า (หรือค้นหา shrine ในคอมพิวเตอร์) เพื่อเปิดโครงการ Shrine
- รอสักครู่เพื่อให้ Android Studio สร้างและซิงค์โปรเจ็กต์ ดังที่แสดงโดยสัญญาณบอกสถานะกิจกรรมที่ด้านล่างของหน้าต่าง Android Studio
- ณ จุดนี้ Android Studio อาจแสดงข้อผิดพลาดบางอย่างในเวอร์ชันเนื่องจากคุณไม่มี Android SDK หรือเครื่องมือสร้างบิลด์ ดังตัวอย่างด้านล่าง ทำตามวิธีการใน Android Studio เพื่อติดตั้ง/อัปเดตโปรเจ็กต์เหล่านี้ และซิงค์โปรเจ็กต์
เพิ่มทรัพยากร Dependency ของโปรเจ็กต์
โปรเจ็กต์ต้องขึ้นอยู่กับไลบรารีการสนับสนุนของ AndroidC สำหรับ Android โค้ดตัวอย่างที่คุณดาวน์โหลดควรมีการระบุทรัพยากร Dependency นี้อยู่แล้ว แต่ขอแนะนำให้ทำตามขั้นตอนต่อไปนี้เพื่อให้มั่นใจว่าโค้ดดังกล่าว
- ไปยังไฟล์ build.gradleของโมดูลappและตรวจสอบว่าการบล็อกdependenciesมีทรัพยากร Dependency ใน MDC Android ดังนี้
api 'com.google.android.material:material:1.1.0-alpha06'
- (ไม่บังคับ) หากจำเป็น ให้แก้ไขไฟล์ 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'
}
เรียกใช้แอปเริ่มต้น
| 
 | 
สำเร็จ! คุณควรเห็นหน้าการเข้าสู่ระบบ Shrine จาก Codelab ของ MDC-101

เมื่อหน้าจอการเข้าสู่ระบบดูดีแล้ว เรามาลองเพิ่มผลิตภัณฑ์ลงในแอปกัน
3. เพิ่มแถบแอปด้านบน
หน้าจอหลักจะแสดงขึ้นมาเมื่อปิดหน้าการเข้าสู่ระบบ โดยมีหน้าจอระบุว่า "คุณทำได้แล้ว!" เยี่ยมเลย แต่ตอนนี้ผู้ใช้ไม่ได้ดำเนินการใดๆ หรือคิดว่าตัวเองอยู่ที่ใดในแอป เรามาเพิ่มการนำทางกันดีกว่า
ดีไซน์ Material มีรูปแบบการนำทางที่ช่วยให้คุณใช้งานได้ง่าย หนึ่งในคอมโพเนนต์การนำทางที่โดดเด่นที่สุดคือแถบแอปด้านบน
มาเพิ่มแถบแอปด้านบนกัน เพื่อให้สามารถนำทางและให้ผู้ใช้เข้าถึงการทำงานอื่นๆ ได้อย่างรวดเร็ว
เพิ่มวิดเจ็ต 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
เราจะจัดรูปแบบแถบแอปด้านบนและเพิ่มปุ่มการทำงานลงในเมนูแบบเป็นโปรแกรม
ก่อนอื่น ให้สร้างวิธีตั้งค่าแถบเครื่องมือ เมธอดนี้ควรได้รับการอ้างอิงไปยังแถบเครื่องมือโดยใช้ id รวมถึงรับการอ้างอิงกิจกรรมโดยใช้ getActivity() ด้วย หากกิจกรรมไม่เป็นค่าว่าง ให้ตั้งค่า Toolbar เพื่อใช้เป็น ActionBar โดยใช้ setSupportActionBar ดังนี้
ProductGridFragment.java
private void setUpToolbar(View view) {
   Toolbar toolbar = view.findViewById(R.id.app_bar);
   AppCompatActivity activity = (AppCompatActivity) getActivity();
   if (activity != null) {
       activity.setSupportActionBar(toolbar);
   }
}
ถัดไป ใต้เมธอด setUpToolbar ที่เราเพิ่งเพิ่มไว้ เรามาลบล้าง onCreateOptionsMenu เพื่อเพิ่มเนื้อหาของ shr_toolbar_menu.xml ลงในแถบเครื่องมือให้สูงเกินจริง
ProductGridFragment.java
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater menuInflater) {
   menuInflater.inflate(R.menu.shr_toolbar_menu, menu);
   super.onCreateOptionsMenu(menu, menuInflater);
}
ตอนนี้ให้เพิ่มการเรียกไปยังเมธอด setUpToolbar ที่เราเพิ่มลงในเนื้อหาของเมธอด onCreateView() ด้วยค่าต่อไปนี้
ProductGridFragment.java
@Override
public View onCreateView(
       @NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
   // Inflate the layout for this fragment with the ProductGrid theme
   View view = inflater.inflate(R.layout.shr_product_grid_fragment, container, false);
   // Set up the toolbar
   setUpToolbar(view);
   return view;
}
สุดท้าย เพิ่มเมธอด onCreate() ลงใน ProductGridFragment.java ในส่วนเนื้อหาของเมธอด ให้ตั้งค่าพารามิเตอร์ setHasOptionMenu เป็น true
วิธีการควรมีลักษณะดังนี้
ProductGridFragment.java
@Override
public void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   setHasOptionsMenu(true);
}
โค้ดข้างต้นตั้งค่าแถบแอปจากเลย์เอาต์ XML ของเราให้เป็นแถบการทำงานสำหรับกิจกรรมนี้ การติดต่อกลับ onCreateOptionsMenu จะบอกกิจกรรมที่จะต้องใช้เป็นเมนู ในกรณีนี้ ระบบจะวางรายการในเมนูจาก R.menu.shr_toolbar_menu ในแถบแอป
ไฟล์เมนูมี 2 รายการ ได้แก่ "ค้นหา" และ "ตัวกรอง"
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.java ของคุณควรมีลักษณะดังนี้
ProductGridFragment.java
package com.google.codelabs.mdc.java.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 android.widget.Toolbar;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
public class ProductGridFragment extends Fragment {
   @Override
   public void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setHasOptionsMenu(true);
   }
  
   @Override
   public View onCreateView(
           @NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
       // Inflate the layout for this fragment with the ProductGrid theme
       View view = inflater.inflate(R.layout.shr_product_grid_fragment, container, false);
       // Set up the toolbar
       setUpToolbar(view);
       return view;
   }
  
   private void setUpToolbar(View view) {
       Toolbar toolbar = view.findViewById(R.id.app_bar);
       AppCompatActivity activity = (AppCompatActivity) getActivity();
       if (activity != null) {
           activity.setSupportActionBar(toolbar);
       }
   }
   @Override
   public void onCreateOptionsMenu(Menu menu, MenuInflater menuInflater) {
       menuInflater.inflate(R.menu.shr_toolbar_menu, menu);
       super.onCreateOptionsMenu(menu, menuInflater);
   }
}
สร้างและเรียกใช้ หน้าจอหลักควรมีลักษณะดังนี้

ตอนนี้แถบเครื่องมือจะมีไอคอนการนำทาง ชื่อ และไอคอนการทำงาน 2 ไอคอนอยู่ทางด้านขวา นอกจากนี้ แถบเครื่องมือจะแสดงระดับความสูงโดยใช้เงาเล็กน้อย ซึ่งแสดงว่าเลเยอร์อยู่บนเลเยอร์ที่แตกต่างจากเนื้อหา
4. เพิ่มบัตร
ตอนนี้แอปมีโครงสร้างแล้ว ลองจัดระเบียบเนื้อหาโดยใส่ในการ์ด
เพิ่มบัตร
เริ่มต้นด้วยการเพิ่มการ์ด 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>
สร้างและเรียกใช้

ในตัวอย่างนี้ คุณจะพบว่าการ์ดถูกฝังจากขอบด้านซ้ายของหน้าจอ และมีมุมโค้งมนและมีเงา (ซึ่งแสดงระดับความสูงของการ์ด) พื้นที่ทั้งหมดเรียกว่า "คอนเทนเนอร์" นอกจากตัวคอนเทนเนอร์แล้ว องค์ประกอบทั้งหมดภายในคอนเทนเนอร์นั้นยังไม่บังคับอีกด้วย
คุณสามารถเพิ่มองค์ประกอบต่อไปนี้ลงในคอนเทนเนอร์: ข้อความส่วนหัว ภาพขนาดย่อหรืออวาตาร์ ข้อความส่วนหัวย่อย เส้นแบ่ง ตลอดจนปุ่มและไอคอน ตัวอย่างเช่น การ์ดที่เราเพิ่งสร้างขึ้นมี TextView 2 แถบ (รายการหนึ่งสำหรับชื่อ และอีกรายการหนึ่งสำหรับข้อความรอง) ใน LinearLayout ซึ่งจัดไว้ที่ด้านล่างของการ์ด
การ์ดมักจะแสดงในคอลเล็กชันร่วมกับการ์ดอื่นๆ ในส่วนถัดไปของ Codelab นี้ เราจะแสดงคอลเล็กชันเป็นคอลเล็กชันในตารางกริด
5. สร้างตารางกริดของการ์ด
เมื่อมีการ์ดหลายใบในหน้าจอเดียว ระบบจะจัดกลุ่มการ์ดเหล่านั้นเป็นคอลเล็กชันอย่างน้อย 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.java
package com.google.codelabs.mdc.java.shrine;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.google.codelabs.mdc.java.shrine.network.ImageRequester;
import com.google.codelabs.mdc.java.shrine.network.ProductEntry;
import java.util.List;
/**
* Adapter used to show a simple grid of products.
*/
public class ProductCardRecyclerViewAdapter extends RecyclerView.Adapter<ProductCardViewHolder> {
   private List<ProductEntry> productList;
   private ImageRequester imageRequester;
   ProductCardRecyclerViewAdapter(List<ProductEntry> productList) {
       this.productList = productList;
       imageRequester = ImageRequester.getInstance();
   }
   @NonNull
   @Override
   public ProductCardViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
       View layoutView = LayoutInflater.from(parent.getContext()).inflate(R.layout.shr_product_card, parent, false);
       return new ProductCardViewHolder(layoutView);
   }
   @Override
   public void onBindViewHolder(@NonNull ProductCardViewHolder holder, int position) {
       // TODO: Put ViewHolder binding code here in MDC-102
   }
   @Override
   public int getItemCount() {
       return productList.size();
   }
}
คลาสอะแดปเตอร์ข้างต้นจะจัดการเนื้อหาของตารางกริด เพื่อดูว่าแต่ละมุมมองควรทำอะไรกับเนื้อหาที่ระบุ เราจะเขียนโค้ดสำหรับ onBindViewHolder() ในไม่ช้า
ในแพ็กเกจเดียวกัน คุณสามารถดู ProductCardViewHolder ได้ด้วย คลาสนี้จะจัดเก็บมุมมองที่ส่งผลต่อเลย์เอาต์การ์ดของเราไว้ เพื่อให้เราสามารถแก้ไขได้ในภายหลัง
ProductCardViewHolder.java
package com.google.codelabs.mdc.java.shrine;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import android.view.View;
public class ProductCardViewHolder extends RecyclerView.ViewHolder {
   public ProductCardViewHolder(@NonNull View itemView) {
       super(itemView);
       // TODO: Find and store views from itemView
   }
}
ในการตั้งค่าตารางกริด ก่อนอื่นเราจะนำตัวยึดตำแหน่ง MaterialCardView ออกจาก shr_product_grid_fragment.xml ถัดไป คุณควรเพิ่มคอมโพเนนต์ที่แสดงถึงตารางการ์ดของเรา ในกรณีนี้ ให้เพิ่มคอมโพเนนต์ 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.java หลังจากเรียกใช้ setUpToolbar(view) และก่อนคำสั่ง return ดังนี้
ProductGridFragment.java
@Override
public View onCreateView(
       @NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
   ...
   setUpToolbar(view);
   // Set up the RecyclerView
   RecyclerView recyclerView = view.findViewById(R.id.recycler_view);
   recyclerView.setHasFixedSize(true);
   recyclerView.setLayoutManager(new GridLayoutManager(getContext(), 2, GridLayoutManager.VERTICAL, false));
   ProductCardRecyclerViewAdapter adapter = new ProductCardRecyclerViewAdapter(
           ProductEntry.initProductEntryList(getResources()));
   recyclerView.setAdapter(adapter);
   int largePadding = getResources().getDimensionPixelSize(R.dimen.shr_product_grid_spacing);
   int smallPadding = getResources().getDimensionPixelSize(R.dimen.shr_product_grid_spacing_small);
   recyclerView.addItemDecoration(new ProductGridItemDecoration(largePadding, smallPadding));
   return view;
}
ข้อมูลโค้ดด้านบนมีขั้นตอนการเริ่มต้นที่จําเป็นในการตั้งค่า RecyclerView ซึ่งรวมถึงการตั้งค่าเครื่องมือจัดการรูปแบบของ RecyclerView รวมถึงการเริ่มต้นและการตั้งค่าอะแดปเตอร์ของ RecyclerView
ไฟล์ ProductGridFragment.java ของคุณควรมีลักษณะดังนี้
ProductGridFragment.java
package com.google.codelabs.mdc.java.shrine;
import android.os.Bundle;
import androidx.recyclerview.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toolbar;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.GridLayoutManager;
import com.google.codelabs.mdc.java.shrine.network.ProductEntry;
public class ProductGridFragment extends Fragment {
   @Override
   public void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setHasOptionsMenu(true);
   }
   @Override
   public View onCreateView(
           @NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
       // Inflate the layout for this fragment with the ProductGrid theme
       View view = inflater.inflate(R.layout.shr_product_grid_fragment, container, false);
       // Set up the toolbar
       setUpToolbar(view);
       // Set up the RecyclerView
       RecyclerView recyclerView = view.findViewById(R.id.recycler_view);
       recyclerView.setHasFixedSize(true);
       recyclerView.setLayoutManager(new GridLayoutManager(getContext(), 2, GridLayoutManager.VERTICAL, false));
       ProductCardRecyclerViewAdapter adapter = new ProductCardRecyclerViewAdapter(
               ProductEntry.initProductEntryList(getResources()));
       recyclerView.setAdapter(adapter);
       int largePadding = getResources().getDimensionPixelSize(R.dimen.shr_product_grid_spacing);
       int smallPadding = getResources().getDimensionPixelSize(R.dimen.shr_product_grid_spacing_small);
       recyclerView.addItemDecoration(new ProductGridItemDecoration(largePadding, smallPadding));
       return view;
   }
   private void setUpToolbar(View view) {
       Toolbar toolbar = view.findViewById(R.id.app_bar);
       AppCompatActivity activity = (AppCompatActivity) getActivity();
       if (activity != null) {
           activity.setSupportActionBar(toolbar);
       }
   }
   @Override
   public void onCreateOptionsMenu(Menu menu, MenuInflater menuInflater) {
       menuInflater.inflate(R.menu.shr_toolbar_menu, menu);
       super.onCreateOptionsMenu(menu, menuInflater);
   }
}
สร้างและเรียกใช้
บัตรพร้อมใช้งานแล้ว ตอนนี้เรายังไม่แสดงข้อมูลใดเลย มาเพิ่มข้อมูลผลิตภัณฑ์กัน
เพิ่มรูปภาพและข้อความ
เพิ่มรูปภาพ ชื่อผลิตภัณฑ์ และราคาในการ์ดแต่ละรายการ ViewHolder Abstraction ของเรามีมุมมองสำหรับการ์ดแต่ละใบ ใน ViewHolder ให้เพิ่มมุมมอง 3 รายการดังนี้
ProductCardViewHolder.java
package com.google.codelabs.mdc.java.shrine;
import androidx.recyclerview.widget.RecyclerView;
import android.view.View;
import android.widget.TextView;
import androidx.annotation.NonNull;
import com.android.volley.toolbox.NetworkImageView;
public class ProductCardViewHolder extends RecyclerView.ViewHolder {
   public NetworkImageView productImage;
   public TextView productTitle;
   public TextView productPrice;
   public ProductCardViewHolder(@NonNull View itemView) {
       super(itemView);
       productImage = itemView.findViewById(R.id.product_image);
       productTitle = itemView.findViewById(R.id.product_title);
       productPrice = itemView.findViewById(R.id.product_price);
   }
}
ในอะแดปเตอร์ของ RecyclerView ใน ViewHolder, ให้อัปเดตเมธอด onBindViewHolder() เพื่อตั้งค่าข้อมูลของแต่ละมุมมอง ดังนี้
ProductCardRecyclerViewAdapter.java
@Override
public void onBindViewHolder(@NonNull ProductCardViewHolder holder, int position) {
   if (productList != null && position < productList.size()) {
       ProductEntry product = productList.get(position);
       holder.productTitle.setText(product.title);
       holder.productPrice.setText(product.price);
       imageRequester.setImageFromUrl(holder.productImage, product.url);
   }
}
รหัสด้านบนจะบอกอะแดปเตอร์ของ RecyclerView ว่าต้องทำอะไรกับบัตรแต่ละใบโดยใช้ ViewHolder
ซึ่งจะกำหนดข้อมูลข้อความบน TextView แต่ละรายการของ ViewHolder และเรียก ImageRequester เพื่อรับรูปภาพจาก URL ImageRequester เป็นชั้นเรียนที่เราจัดเตรียมไว้ให้เพื่อความสะดวกของคุณ และใช้ไลบรารี Volley (หัวข้อที่อยู่นอกขอบเขตของ Codelab นี้ แต่คุณสามารถสำรวจโค้ดด้วยตนเองได้)
สร้างและเรียกใช้

ตอนนี้ผลิตภัณฑ์ของเราปรากฏในแอปแล้ว
6. สรุป
แอปของเรามีขั้นตอนพื้นฐานที่จะนำผู้ใช้จากหน้าจอเข้าสู่ระบบไปยังหน้าจอหลักที่แสดงผลิตภัณฑ์ได้ เพียงเขียนโค้ดเพียงไม่กี่บรรทัด เราได้เพิ่มแถบแอปด้านบนพร้อมชื่อและปุ่ม 3 ปุ่ม และตารางการ์ดเพื่อนำเสนอเนื้อหาของแอป ตอนนี้หน้าจอหลักของเราเรียบง่ายและใช้งานได้จริง ด้วยโครงสร้างพื้นฐานแบบพื้นฐานและเนื้อหาที่นำไปใช้ได้จริง
ขั้นตอนถัดไป
ด้วยแถบแอป การ์ด ช่องข้อความ และปุ่มด้านบน ตอนนี้เราได้ใช้องค์ประกอบหลัก 4 รายการของดีไซน์ Material จากไลบรารี MDC-Android คุณสำรวจคอมโพเนนต์อื่นๆ เพิ่มเติมได้ในคอมโพเนนต์ของแคตตาล็อก MDC-Android ใน MDC Android
แม้ว่าแอปจะทำงานได้อย่างเต็มรูปแบบ แต่แอปของเราไม่ได้แสดงแบรนด์ที่เฉพาะเจาะจงใดๆ ใน MDC-103: Material Design Theming with Color, Shape, Elevation และ Type เราจะปรับแต่งสไตล์ของส่วนประกอบเหล่านี้เพื่อแสดงออกถึงแบรนด์ที่มีชีวิตชีวาและทันสมัย
