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

1. مقدمة

logo_components_color_2x_web_96dp.png

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

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

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

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

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

249db074eff043f4.png

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

  • AppBarLayout
  • MaterialCardView

المتطلبات

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

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

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

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

هل تريد المتابعة من MDC-101؟

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

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

تنزيل تطبيق "الدرس التطبيقي حول الترميز" للمبتدئين

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

KzoYWC1S7Se7yL8igi1vXF_mbVxAdl2lg5kb7RODrsVpEng0G6U3NK1Qnn0faBBZd2u71yMXioy9tD-7fv3NXvVO4N3EtMMeWDTmqBMMl6egd9R5uXX0T_SKmahbmRor3wZZHX0ByA

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

يجب أن يعتمد المشروع على مكتبة دعم 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.

4cb0c218948144b4.png

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

3- إضافة شريط تطبيق في أعلى الشاشة

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

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

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

إضافة تطبيق مصغّر لشريط التطبيقات

في 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، تُعرف هذه باسم أزرار الإجراءات. سنصمّم شريط التطبيق العلوي ونضيف أزرار الإجراءات إلى قائمته آليًا.

في الدالة onCreateView الخاصة بـ ProductGridFragment.kt، اضبط Toolbar في activity لاستخدامه كـ ActionBar باستخدام setSupportActionBar. يمكنك إجراء ذلك بعد إنشاء الملف الشخصي باستخدام inflater.

ProductGridFragment.kt

override fun onCreateView(
       inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
   // Inflate the layout for this fragment with the ProductGrid theme
   val view = inflater.inflate(R.layout.shr_product_grid_fragment, container, false)

   // Set up the toolbar.
   (activity as AppCompatActivity).setSupportActionBar(view.app_bar)

   return view;
}

بعد ذلك، أسفل الطريقة التي غيّرناها للتو لإعداد شريط الأدوات، لنلغي onCreateOptionsMenu لتضخيم محتوى shr_toolbar_menu.xml في شريط الأدوات:

ProductGridFragment.kt

override fun onCreateOptionsMenu(menu: Menu, menuInflater: MenuInflater) {
   menuInflater.inflate(R.menu.shr_toolbar_menu, menu)
   super.onCreateOptionsMenu(menu, menuInflater)
}

أخيرًا، يمكنك إلغاء onCreate() في ProductGridFragment.kt، وبعد الاتصال بـ super()، يمكنك الاتصال بـ setHasOptionMenu باستخدام true:

ProductGridFragment.kt

override fun onCreate(savedInstanceState: Bundle?) {
   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.kt على النحو التالي:

ProductGridFragment.kt

package com.google.codelabs.mdc.kotlin.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 androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.GridLayoutManager
import com.google.codelabs.mdc.kotlin.shrine.network.ProductEntry
import kotlinx.android.synthetic.main.shr_product_grid_fragment.view.*

class ProductGridFragment : Fragment() {

   override fun onCreate(savedInstanceState: Bundle?) {
       super.onCreate(savedInstanceState)
       setHasOptionsMenu(true)
   }

   override fun onCreateView(
           inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
       // Inflate the layout for this fragment with the ProductGrid theme
       val view = inflater.inflate(R.layout.shr_product_grid_fragment, container, false)

       // Set up the tool bar
       (activity as AppCompatActivity).setSupportActionBar(view.app_bar)

       return view;
   }

   override fun 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.kt

package com.google.codelabs.mdc.kotlin.shrine

import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView

import com.google.codelabs.mdc.kotlin.shrine.network.ProductEntry

/**
* Adapter used to show a simple grid of products.
*/
class ProductCardRecyclerViewAdapter(private val productList: List<ProductEntry>) : RecyclerView.Adapter<ProductCardViewHolder>() {

   override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ProductCardViewHolder {
       val layoutView = LayoutInflater.from(parent.context).inflate(R.layout.shr_product_card, parent, false)
       return ProductCardViewHolder(layoutView)
   }

   override fun onBindViewHolder(holder: ProductCardViewHolder, position: Int) {
       // TODO: Put ViewHolder binding code here in MDC-102
   }

   override fun getItemCount(): Int {
       return productList.size
   }
}

تدير فئة المُحوِّل أعلاه محتوى الشبكة. لتحديد الإجراءات التي يجب أن يتّخذها كل عرض مع المحتوى المحدّد، سنكتب قريبًا الرمز البرمجي لـ onBindViewHolder().

في الحزمة نفسها، يمكنك أيضًا الاطّلاع على ProductCardViewHolder. تخزِّن هذه الفئة طرق العرض التي تؤثّر في تنسيق البطاقة، حتى نتمكّن من تعديلها لاحقًا.

ProductCardViewHolder.kt

package com.google.codelabs.mdc.kotlin.shrine

import android.view.View
import androidx.recyclerview.widget.RecyclerView

class ProductCardViewHolder(itemView: View) //TODO: Find and store views from itemView
   : RecyclerView.ViewHolder(itemView)

لإعداد الشبكة، نرغب أولاً في إزالة العنصر النائب MaterialCardView من shr_product_grid_fragment.xml. بعد ذلك، يجب عليك إضافة المكون الذي يمثل شبكة البطاقات الخاصة بنا. في هذه الحالة، سنستخدم RecyclerView. أضِف مكوّن 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.kt بعد طلب setUpToolbar(view) وقبل عبارة return:

ProductGridFragment.kt

override fun onCreateView(
       inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
   // Inflate the layout for this fragment with the ProductGrid theme
   val view = inflater.inflate(R.layout.shr_product_grid_fragment, container, false)

   // Set up the toolbar.
   (activity as AppCompatActivity).setSupportActionBar(view.app_bar)

   // Set up the RecyclerView
   view.recycler_view.setHasFixedSize(true)
   view.recycler_view.layoutManager = GridLayoutManager(context, 2, RecyclerView.VERTICAL, false)
   val adapter = ProductCardRecyclerViewAdapter(
           ProductEntry.initProductEntryList(resources))
   view.recycler_view.adapter = adapter
   val largePadding = resources.getDimensionPixelSize(R.dimen.shr_product_grid_spacing)
   val smallPadding = resources.getDimensionPixelSize(R.dimen.shr_product_grid_spacing_small)
   view.recycler_view.addItemDecoration(ProductGridItemDecoration(largePadding, smallPadding))

   return view;
}

يحتوي مقتطف الرمز أعلاه على خطوات الإعداد اللازمة لإعداد RecyclerView. يتضمّن ذلك إعداد مدير تنسيق "RecyclerView"، بالإضافة إلى إعداد محوّل "RecyclerView" وضبطه.

من المفترض أن يظهر ملف ProductGridFragment.kt الآن على النحو التالي:

ProductGridFragment .kt

package com.google.codelabs.mdc.kotlin.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 androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.google.codelabs.mdc.kotlin.shrine.network.ProductEntry
import kotlinx.android.synthetic.main.shr_product_grid_fragment.view.*

class ProductGridFragment : Fragment() {

   override fun onCreate(savedInstanceState: Bundle?) {
       super.onCreate(savedInstanceState)
       setHasOptionsMenu(true)
   }

   override fun onCreateView(
           inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
       // Inflate the layout for this fragment with the ProductGrid theme
       val view = inflater.inflate(R.layout.shr_product_grid_fragment, container, false)

       // Set up the toolbar.
       (activity as AppCompatActivity).setSupportActionBar(view.app_bar)

       // Set up the RecyclerView
       view.recycler_view.setHasFixedSize(true)
       view.recycler_view.layoutManager = GridLayoutManager(context, 2, RecyclerView.VERTICAL, false)
       val adapter = ProductCardRecyclerViewAdapter(
               ProductEntry.initProductEntryList(resources))
       view.recycler_view.adapter = adapter
       val largePadding = resources.getDimensionPixelSize(R.dimen.shr_product_grid_spacing)
       val smallPadding = resources.getDimensionPixelSize(R.dimen.shr_product_grid_spacing_small)
       view.recycler_view.addItemDecoration(ProductGridItemDecoration(largePadding, smallPadding))

       return view;
   }

   override fun onCreateOptionsMenu(menu: Menu, menuInflater: MenuInflater) {
       menuInflater.inflate(R.menu.shr_toolbar_menu, menu)
       super.onCreateOptionsMenu(menu, menuInflater)
   }
}

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

f9aeab846fc3bb4c.png

لقد ظهرت البطاقات الآن. إنّها لا تعرض أي بيانات حتى الآن، لذا سنضيف بعض بيانات المنتجات.

إضافة صور ونصوص

أضِف صورة واسم المنتج والسعر لكل بطاقة. تُخزِّن ViewHolder المُجمّعة المشاهدات لكل بطاقة. في ViewHolder، أضِف طرق العرض الثلاث على النحو التالي.

ProductCardViewHolder.kt

package com.google.codelabs.mdc.kotlin.shrine

import android.view.View
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView

import com.android.volley.toolbox.NetworkImageView

class ProductCardViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {

   var productImage: NetworkImageView = itemView.findViewById(R.id.product_image)
   var productTitle: TextView = itemView.findViewById(R.id.product_title)
   var productPrice: TextView = itemView.findViewById(R.id.product_price)
}

عدِّل طريقة onBindViewHolder() في ProductCardRecyclerViewAdapter لضبط العنوان والسعر وصورة المنتج لكل طريقة عرض منتج، كما هو موضّح أدناه:

ProductCardRecyclerViewAdapter.kt

override fun onBindViewHolder(holder: ProductCardViewHolder, position: Int) {
   if (position < productList.size) {
       val product = productList[position]
       holder.productTitle.text = product.title
       holder.productPrice.text = 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-103: مظهر التصميم المتعدد الأبعاد حسب اللون والشكل والارتفاع والنوع، سنخصِّص نمط هذه المكوّنات للتعبير عن علامة تجارية عصرية ونابضة بالحياة.

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

أوافق بشدة أوافق محايد لا أوافق لا أوافق أبدًا

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

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