MDC-102 Android: מבנה ופריסה של חומרים (Java)

1. מבוא

logo_components_color_2x_web_96dp.png

Material Components (MDC) עוזר למפתחים להטמיע Material Design. MDC נוצר על ידי צוות של מהנדסים ומעצבי חוויית המשתמש ב-Google, שכולל עשרות רכיבים יפים ופונקציונליים של ממשק המשתמש. זמין ל-Android, ל-iOS, לאינטרנט ול-Flutter.material.io/develop

ב-Codelab MDC-101 השתמשת בשני רכיבי Material (MDC) כדי לבנות דף התחברות: שדות טקסט ולחצנים. עכשיו נרחיב את הבסיס הזה על ידי הוספת ניווט, מבנה ונתונים.

מה תפַתחו

ב-Codelab הזה תבנו מסך בית לאפליקציה בשם Shrine, אפליקציית מסחר אלקטרוני שמוכרת בגדים ומוצרים לבית. היא תכלול:

  • סרגל עליון באפליקציה
  • רשימת מוצרים ברשת

249db074eff043f4.png

MDC-Android MDC-Android

  • 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 ->. מקדש (או לחפש במחשב את מקדש) כדי לפתוח את פרויקט המקדש.
  2. ממתינים רגע עד שמערכת Android Studio תסיים לבנות ולסנכרן את הפרויקט, כפי שמוצג באינדיקטורים של הפעילות בחלק התחתון של החלון של Android Studio.
  3. בשלב הזה, ייתכן שיוצגו ב-Android Studio חלק משגיאות ה-build כי ה-SDK של Android או כלי ה-build חסרים לכם, כמו זה שמוצג למטה. כדי להתקין או לעדכן אותם ולסנכרן את הפרויקט, פועלים לפי ההוראות ב-Android Studio.

F5H6srsw_5xOPGFpKrm1RwgewatxA_HUbDI1PWoQUAoJcT6DpfBOkAYwq3S-2vUHvweUaFgAmG7BtUKkGouUbhTwXQh53qec8tO5eVecdlo7QIoLc8rNxFEBb8l7RlS-KzBbZOzVhA

הוספת יחסי תלות של פרויקטים

הפרויקט צריך להיות תלוי בספריית התמיכה של MDC ל-Android. הקוד לדוגמה שהורדתם כבר אמור לכלול את התלות הזאת, אבל כדאי לבצע את השלבים הבאים כדי לוודא זאת.

  1. עוברים לקובץ build.gradle של המודול app ומוודאים שהבלוק 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. מוודאים שתצורת ה-build שמשמאל ללחצן ההפעלה / ההפעלה היא app.
  2. לוחצים על לחצן ההפעלה / ההפעלה כדי לבנות את האפליקציה ולהפעיל אותה.
  3. בחלון בחירת יעד פריסה, אם כבר יש לכם מכשיר Android שרשום ברשימת המכשירים הזמינים, מדלגים לשלב 8. אחרת, לוחצים על יצירת מכשיר וירטואלי חדש.
  4. במסך בחירת חומרה, בוחרים מכשיר טלפון, כמו Pixel 2, ולוחצים על הבא.
  5. במסך תמונת המערכת, בוחרים גרסת Android האחרונה, רצוי רמת ה-API הגבוהה ביותר. אם היא לא מותקנת, לוחצים על הקישור הורדה שמופיע ומשלימים את ההורדה.
  6. לוחצים על הבא.
  7. במסך מכשיר וירטואלי של Android (AVD), משאירים את ההגדרות כפי שהן ולוחצים על סיום.
  8. בוחרים מכשיר Android מתיבת הדו-שיח של יעד הפריסה.
  9. לוחצים על אישור.
  10. על ידי Android Studio מפתחים את האפליקציה, פורסים אותה ופותחים אותה באופן אוטומטי במכשיר היעד.

הצלחת! דף ההתחברות לאתר אמור להופיע ב-MDC-101 Codelab.

4cb0c218948144b4.png

עכשיו, כשמסך ההתחברות נראה טוב, כדאי לאכלס את האפליקציה במוצרים.

3. הוספת סרגל אפליקציה עליון

מסך הבית נחשף כשדף ההתחברות נסגר, עם מסך שכתוב בו "הצלחת!". נהדר! אבל עכשיו למשתמש שלנו אין שום פעולה לבצע, ואין לו מושג איפה הוא נמצא באפליקציה. כדי לעזור בכך, אפשר להוסיף את תכונת הניווט.

עיצוב חדשני (Material Design) כולל דפוסי ניווט שמבטיחים רמה גבוהה של נוחות השימוש. אחד מרכיבי הניווט הבולטים ביותר הוא סרגל האפליקציה העליון.

כדי לאפשר ניווט ולתת למשתמשים גישה מהירה לפעולות אחרות, כדאי להוסיף סרגל עליון באפליקציה.

הוספת ווידג'ט של 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(). אם הפעילות לא מוגדרת כ-null, צריך להגדיר את 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);
}

עכשיו מוסיפים קריאה ל-method 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. בגוף ה-method, מגדירים את הפרמטר setHasOptionMenu כ-true.

השיטה אמורה להיראות כך:

ProductGridFragment.java

@Override
public void onCreate(Bundle savedInstanceState) {
   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.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

עכשיו סרגל הכלים כולל סמל ניווט, כותרת ושני סמלי פעולות בצד שמאל. סרגל הכלים גם מציג גובה באמצעות צל עדין, המציין שהוא נמצא בשכבה שונה מהתוכן.

4. הוספת כרטיס

עכשיו, אחרי שיש לאפליקציה שלנו מבנה כלשהו, נארגן את התוכן על ידי הצבתו בכרטיסים.

הוספת כרטיס

כדי להתחיל, מוסיפים כרטיס אחד מתחת לסרגל האפליקציות העליון. כרטיס צריך לכלול אזור לתמונה, כותרת ותווית לטקסט משני.

ב-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 (אחת לכותרת ואחת לטקסט משני) בתוך LinearLayout, שממולאות בחלק התחתון של הכרטיס.

בדרך כלל הכרטיסים מוצגים באוסף יחד עם כרטיסים אחרים. בקטע הבא ב-Codelab הזה, נפרוס אותם כאוסף ברשת.

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, שמאפשר לכלול תמונות מכתובת URL), ושני TextViews.

בשלב הבא, כדאי לעיין ב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
   }
}

כדי להגדיר את הרשת שלנו, קודם אנחנו רוצים להסיר את ה-placeholder 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 מפורטות הצפיות בכל כרטיס. ב-ViewHolder שלנו, צריך להוסיף את שלוש התצוגות הבאות באופן הבא:

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, מעדכנים את ה-method 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. Recap

באפליקציה שלנו יש תהליך בסיסי שמעביר את המשתמש ממסך ההתחברות למסך הבית, שבו ניתן לצפות במוצרים. בכמה שורות קוד בלבד הוספנו סרגל אפליקציה עליון עם כותרת ושלושה לחצנים, ורשת של כרטיסים להצגת התוכן של האפליקציה. מסך הבית שלנו עכשיו פשוט ופונקציונלי, עם מבנה בסיסי ותוכן פרקטי.

השלבים הבאים

באמצעות הסרגל, הכרטיס, שדה הטקסט והלחצן העליונים של האפליקציה, השתמשנו עכשיו בארבעה רכיבי ליבה של Material Design מהספרייה MDC-Android! אפשר לעיין בהרבה יותר רכיבים ברכיבי הקטלוג של MDC-Android ב-MDC Android.

למרות שהיא פעילה באופן מלא, האפליקציה שלנו לא מבטאת עדיין מותג מסוים. במשחק MDC-103: עיצוב חומרים בעיצוב חדשני עם צבע, צורה, גובה וסוג, נתאים אישית את הסגנון של הרכיבים האלה כדי לבטא מותג מודרני ותוסס.

הצלחתי להשלים את ה-Codelab הזה תוך השקעה של זמן ומאמץ סבירים

נכון מאוד נכון נייטרלי לא נכון לא נכון בכלל

ארצה להמשיך להשתמש ברכיבי Material Materials בעתיד

נכון מאוד נכון נייטרלי לא נכון לא נכון בכלל