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

1. مقدمة

logo_components_color_2x_web_96dp.png

تساعد المكونات المادية (MDC) المطورين على تنفيذ التصميم المتعدد الأبعاد. يضم مركز MDC، الذي أنشأه فريق من المهندسين ومصممي تجربة المستخدم في Google، عشرات من مكونات واجهة المستخدم الجميلة والعملية، وهو متاح لأجهزة Android وiOS والويب وFlutter.material.io/develop

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

ما الذي ستنشئه

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

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

249db074eff043f4.png

MDC-Android MDC-Android

  • AppBarLayout
  • MaterialCardView

المتطلبات

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

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

حديث متوسط بارع

2. إعداد بيئة التطوير

هل تريد المتابعة من 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 -> ضريح (أو ابحث في جهاز الكمبيوتر عن ضريح) لفتح مشروع الضريح.
  2. انتظِر قليلاً حتى ينشئ "استوديو Android" المشروع ويزامنه، كما هو موضّح من خلال مؤشرات النشاط أسفل نافذة "استوديو Android".
  3. في هذه المرحلة، قد يعرض "استوديو Android" بعض أخطاء الإصدار بسبب عدم توفُّر حزمة تطوير البرامج (SDK) لنظام التشغيل Android أو أدوات الإصدار، مثل الأداة الموضّحة أدناه. اتّبِع التعليمات الواردة في "استوديو Android" لتثبيت هذه العناصر أو تحديثها ومزامنة مشروعك.

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

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

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(). إذا لم يكن النشاط فارغًا، اضبط 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);
   }

}

البناء والتشغيل. يُفترض أن تظهر شاشتك الرئيسية على النحو التالي:

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، مع المحاذاة إلى أسفل البطاقة.

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

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

لإعداد الشبكة، نرغب أولاً في إزالة العنصر النائب 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,، يمكنك تعديل طريقة 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 (هذا موضوع خارج نطاق هذا الدرس التطبيقي حول الترميز، ولكن يمكنك استكشاف الرمز بنفسك).

الإنشاء والتشغيل:

249db074eff043f4.png

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

6- ملخّص

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

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

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

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

تمكنتُ من إكمال هذا الدرس التطبيقي حول الترميز بقدرٍ معقول من الوقت والجهد

أوافق بشدة أوافق ليست دقيقة ولا غير دقيقة لا أوافق لا أوافق أبدًا

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

أوافق بشدة أوافق ليست دقيقة ولا غير دقيقة لا أوافق لا أوافق أبدًا