MDC-102 Android: بنية المواد وتخطيطها (Java)

logo_components_color_2x_web_96dp.png

تساعد Material Components (MDC) المطوّرين في تنفيذ Material Design. تم إنشاء MDC بواسطة فريق من المهندسين ومصممي تجربة المستخدم في Google، وتتضمّن عشرات المكوّنات الجميلة والوظيفية لواجهة المستخدم، وهي متاحة على Android وiOS والويب وFlutter.

material.io/develop

في الدرس التطبيقي حول الترميز MDC-101، استخدمت مكوّنَين من "مكوّنات التصميم المتعدد الأبعاد" (MDC) لإنشاء صفحة تسجيل دخول: حقول نصية وأزرار. والآن، لنوسّع نطاق هذا الأساس من خلال إضافة عناصر التنقّل والبنية والبيانات.

ما ستنشئه

في هذا الدرس التطبيقي حول الترميز، ستنشئ شاشة رئيسية لتطبيق يُسمى Shrine، وهو تطبيق للتجارة الإلكترونية يبيع الملابس والسلع المنزلية. ستتضمّن هذه الرسالة ما يلي:

  • شريط تطبيق علوي
  • قائمة شبكية للمنتجات

مكوّنات MDC-Android في هذا الدرس التطبيقي حول الترميز

  • AppBarLayout
  • MaterialCardView

المتطلبات

  • معرفة أساسية بتطوير تطبيقات Android
  • استوديو Android (يمكنك تنزيله من هنا إذا لم يكن مثبّتًا لديك)
  • محاكي Android أو جهاز Android (متاح من خلال Android Studio)
  • الرمز النموذجي (راجِع الخطوة التالية)

ما هو تقييمك لمستوى خبرتك في إنشاء تطبيقات Android؟

مبتدئ متوسط متقدّم

هل سبق لك المشاركة في دورة MDC-101؟

إذا أكملت دورة MDC-101 التدريبية، من المفترض أن يكون الرمز البرمجي جاهزًا لاستخدامه في هذا الدرس العملي. يمكنك الانتقال إلى الخطوة 3: إضافة شريط تطبيق علوي.

هل تريد البدء من الصفر؟

تنزيل تطبيق الدرس التطبيقي الأوّلي

تنزيل تطبيق المبتدئين

يقع تطبيق البداية في دليل material-components-android-codelabs-102-starter/java. احرص على cd في هذا الدليل قبل البدء.

...أو استنسِخه من GitHub

لاستنساخ هذا الدرس التطبيقي العملي من GitHub، شغِّل الأوامر التالية:

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

تحميل الرمز الأولي في "استوديو Android"

  1. بعد انتهاء معالج الإعداد وظهور النافذة مرحبًا بك في "استوديو Android"، انقر على فتح مشروع حالي في "استوديو Android". انتقِل إلى الدليل الذي ثبّت فيه نموذج الرمز، واختَر java -> shrine (أو ابحث عن shrine على جهاز الكمبيوتر) لفتح مشروع Shrine.
  2. انتظِر لحظة إلى أن ينتهي "استوديو Android" من إنشاء المشروع ومزامنته، كما هو موضّح من خلال مؤشرات النشاط في أسفل نافذة "استوديو Android".
  3. في هذه المرحلة، قد يعرض "استوديو Android" بعض أخطاء الإنشاء لأنّك لم تثبِّت حزمة تطوير البرامج (SDK) لنظام التشغيل Android أو أدوات الإنشاء، مثل تلك الموضّحة أدناه. اتّبِع التعليمات في "استوديو Android" لتثبيت هذه الحِزم أو تعديلها ومزامنة مشروعك.

إضافة تبعيات المشروع

يجب أن يتضمّن المشروع تبعية لمكتبة دعم 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. تأكَّد من أنّ إعدادات الإصدار على يسار زر التشغيل هي app.
  2. اضغط على زر التشغيل / التنفيذ الأخضر لإنشاء التطبيق وتشغيله.
  3. في نافذة اختيار هدف النشر، إذا كان لديك جهاز Android مُدرَج في الأجهزة المتاحة، انتقِل إلى الخطوة 8. بخلاف ذلك، انقر على إنشاء جهاز افتراضي جديد.
  4. في شاشة اختيار الجهاز، اختَر جهاز هاتف، مثل Pixel 2، ثم انقر على التالي.
  5. في شاشة صورة النظام، اختَر إصدارًا حديثًا من Android، ويُفضَّل اختيار أعلى مستوى لواجهة برمجة التطبيقات. إذا لم يكن مثبّتًا، انقر على الرابط تنزيل الذي يظهر وأكمِل عملية التنزيل.
  6. انقر على التالي.
  7. في شاشة جهاز Android الافتراضي (AVD)، اترك الإعدادات كما هي وانقر على إنهاء.
  8. اختَر جهاز Android من مربّع حوار "هدف النشر".
  9. انقر على حسنًا.
  10. ينشئ Android Studio التطبيق وينشره ويفتحه تلقائيًا على الجهاز المستهدف.

اكتمال النقل بنجاح من المفترض أن تظهر صفحة تسجيل الدخول إلى Shrine من برنامج MDC-101 التعليمي.

بعد أن أصبح شكل شاشة تسجيل الدخول جيدًا، لنملأ التطبيق ببعض المنتجات.

تظهر الشاشة الرئيسية عند إغلاق صفحة تسجيل الدخول، مع ظهور رسالة "أحسنت!". رائع. ولكن الآن، لا يمكن للمستخدم اتّخاذ أي إجراءات، ولا يمكنه معرفة مكانه في التطبيق. ولحلّ هذه المشكلة، لنضِف عناصر التنقّل.

يوفّر 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، أضِف ما يلي إلى مكوّن Toolbar XML (الذي أضفته للتو إلى التصميم):

shr_product_grid_fragment.xml

app:navigationIcon="@drawable/shr_menu"

يجب أن يبدو shr_product_grid_fragment.xml على النحو التالي:

shr_product_grid_fragment.xml

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

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

إضافة أزرار الإجراءات وتصميم شريط التطبيق العلوي

يمكنك أيضًا إضافة أزرار إلى الجانب الأخير من شريط التطبيق. في نظام التشغيل Android، تُعرف هذه الأزرار باسم أزرار الإجراءات.

سنصمّم شريط التطبيق العلوي ونضيف أزرار الإجراءات إلى القائمة آليًا.

لنبدأ بإنشاء طريقة لإعداد شريط الأدوات. يجب أن تحصل الطريقة على مرجع إلى شريط الأدوات باستخدام 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 في شريط التطبيق.

يحتوي ملف القائمة على عنصرَين: "بحث" و "فلترة".

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

}

البناء والتنفيذ يجب أن تبدو شاشتك الرئيسية على النحو التالي:

يحتوي شريط الأدوات الآن على رمز تنقّل وعنوان ورمزي إجراء على الجانب الأيسر. يعرض شريط الأدوات أيضًا الارتفاع باستخدام ظل خفيف، ما يشير إلى أنّه يقع في طبقة مختلفة عن المحتوى.

بعد أن أصبح لتطبيقنا بعض البنية، لننظّم المحتوى من خلال وضعه في بطاقات.

إضافة بطاقة

لنبدأ بإضافة بطاقة واحدة أسفل شريط التطبيقات العلوي. يجب أن تحتوي البطاقة على منطقة مخصّصة للصورة وعنوان وتصنيف للنص الثانوي.

في 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 (أحدهما للعنوان والآخر للنص الثانوي) في عنصر LinearLayout، ويتم محاذاتهما إلى أسفل البطاقة.

عادةً ما يتم عرض البطاقات في مجموعة مع بطاقات أخرى. في القسم التالي من هذا الدرس العملي، سنعرضها كمجموعة في شبكة.

عندما تظهر بطاقات متعدّدة على الشاشة، يتم تجميعها معًا في مجموعة واحدة أو أكثر. تكون البطاقات في الشبكة متحدة المستوى، ما يعني أنّها تشترك في الارتفاع نفسه عند عدم التفاعل معها (إلا إذا تم التقاطها أو سحبها، ولكن لن نتناول ذلك في هذا الدرس التطبيقي).

إعداد شبكة البطاقات

اطّلِع على ملف 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
   }
}

لإعداد الشبكة، علينا أولاً إزالة العنصر النائب MaterialCardView من shr_product_grid_fragment.xml. بعد ذلك، عليك إضافة المكوّن الذي يمثّل شبكة البطاقات. في هذه الحالة، أضِف مكوّن RecyclerView إلى shr_product_grid_fragment.xml أسفل مكوّن AppBarLayout XML:

shr_product_grid_fragment.xml

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

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

</androidx.core.widget.NestedScrollView>

يجب أن يبدو shr_product_grid_fragment.xml على النحو التالي:

shr_product_grid_fragment.xml

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

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

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

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

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

   </androidx.core.widget.NestedScrollView>

</FrameLayout>

أخيرًا، في onCreateView()، أضِف رمز تهيئة 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 على عدد المشاهدات لكل بطاقة. في 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، عدِّل طريقة onBindViewHolder() في ViewHolder, لضبط المعلومات في كل طريقة عرض:

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.

هنا يتم ضبط البيانات النصية على كل ViewHolder من TextView، ويتم استدعاء ImageRequester للحصول على صورة من عنوان URL. ‫ImageRequester هي فئة قدّمناها لتسهيل الأمر عليك، وهي تستخدم مكتبة Volley (هذا موضوع خارج نطاق هذا الدرس العملي، ولكن يمكنك استكشاف الرمز البرمجي بنفسك).

إنشاء التطبيق وتشغيله:

تظهر منتجاتنا الآن في التطبيق.

يتضمّن تطبيقنا مسارًا أساسيًا ينقل المستخدم من شاشة تسجيل الدخول إلى الشاشة الرئيسية، حيث يمكن عرض المنتجات. من خلال بضعة أسطر من الرمز البرمجي، أضفنا شريط تطبيق علويًا يتضمّن عنوانًا وثلاثة أزرار، بالإضافة إلى شبكة من البطاقات لعرض محتوى تطبيقنا. أصبحت شاشتنا الرئيسية بسيطة وعملية، وتتضمّن بنية أساسية ومحتوى قابلاً للتنفيذ.

الخطوات التالية

باستخدام شريط التطبيق العلوي والبطاقة وحقل النص والزر، نكون قد استخدمنا الآن أربعة مكوّنات أساسية من Material Design من مكتبة MDC-Android. يمكنك استكشاف المزيد من المكوّنات في "قائمة مكوّنات MDC لنظام التشغيل Android" المكوّنات في MDC لنظام التشغيل Android.

على الرغم من أنّ تطبيقنا يعمل بكامل وظائفه، إلا أنّه لا يعبّر عن أي علامة تجارية معيّنة حتى الآن. في MDC-103: تصميم Material Design باستخدام اللون والشكل والارتفاع والنوع، سنخصّص نمط هذه المكوّنات للتعبير عن علامة تجارية عصرية وحيوية.

لقد تمكّنت من إكمال هذا الدرس العملي البرمجي خلال فترة زمنية معقولة وبجهد معقول

أوافق بشدة أوافق لا أوافق ولا أعارض لا أوافق لا أوافق أبدًا

أريد مواصلة استخدام Material Components في المستقبل

أوافق بشدة أوافق لا أوافق ولا أعارض لا أوافق لا أوافق أبدًا