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

1. บทนำ

logo_components_color_2x_web_96dp.png

Material Components (MDC) ช่วยให้นักพัฒนานำดีไซน์ Material มาใช้ MDC สร้างโดยทีมวิศวกรและนักออกแบบ UX ที่ Google โดยมีคอมโพเนนต์ UI ที่สวยงามและใช้งานได้หลายสิบอย่างและพร้อมใช้งานสำหรับ Android, iOS, เว็บ และ Flutter.material.io/develop

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

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

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

  • แถบแอปด้านบน
  • รายการผลิตภัณฑ์แบบตารางกริด

249db074eff043f4.png

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

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

F5H6srsw_5xOPGFpKrm1RwgewatxA_HUbDI1PWoQUAoJcT6DpfBOkAYwq3S-2vUHvweUaFgAmG7BtUKkGouUbhTwXQh53qec8tO5eVecdlo7QIoLc8rNxFEBb8l7RlS-KzBbZOzVhA

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

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

  1. ไปยังไฟล์ build.gradle ของโมดูล app และตรวจสอบว่าการบล็อก 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. ในหน้าจออุปกรณ์เสมือน (AVD) ของ Android (AVD) ให้ปล่อยการตั้งค่าไว้เหมือนเดิม แล้วคลิกเสร็จสิ้น
  8. เลือกอุปกรณ์ Android จากกล่องโต้ตอบเป้าหมายการทำให้ใช้งานได้
  9. คลิกตกลง
  10. Android Studio จะสร้างแอป ติดตั้งใช้งาน และเปิดแอปในอุปกรณ์เป้าหมายโดยอัตโนมัติ

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

4cb0c218948144b4.png

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

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

}

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

d04e8aa3b27f4754.png

ตอนนี้แถบเครื่องมือจะมีไอคอนการนำทาง ชื่อ และไอคอนการทำงาน 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>

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

f6184a55ccb5f920.png

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

คุณสามารถเพิ่มองค์ประกอบต่อไปนี้ลงในคอนเทนเนอร์: ข้อความส่วนหัว ภาพขนาดย่อหรืออวาตาร์ ข้อความส่วนหัวย่อย เส้นแบ่ง ตลอดจนปุ่มและไอคอน ตัวอย่างเช่น การ์ดที่เราเพิ่งสร้างขึ้นมี 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);
   }

}

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

f9aeab846fc3bb4c.png

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

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

เพิ่มรูปภาพ ชื่อผลิตภัณฑ์ และราคาในการ์ดแต่ละรายการ 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 นี้ แต่คุณสามารถสำรวจโค้ดด้วยตนเองได้)

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

249db074eff043f4.png

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

6. สรุป

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

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

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

แม้ว่าแอปจะทำงานได้อย่างเต็มรูปแบบ แต่แอปของเราไม่ได้แสดงแบรนด์ที่เฉพาะเจาะจงใดๆ ใน MDC-103: Material Design Theming with Color, Shape, Elevation และ Type เราจะปรับแต่งสไตล์ของส่วนประกอบเหล่านี้เพื่อแสดงออกถึงแบรนด์ที่มีชีวิตชีวาและทันสมัย

ฉันทำ Codelab นี้เสร็จได้ โดยใช้เวลาและลงแรงพอสมควร

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

ฉันต้องการใช้คอมโพเนนต์เนื้อหาต่อไปในอนาคต

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