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

1. مقدمة

logo_components_color_2x_web_96dp.png

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

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

ما ستنشئه

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

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

249db074eff043f4.png

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

  • AppBarLayout
  • MaterialCardView

المتطلبات

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

ما هو تقييمك لمستوى خبرتك في إنشاء تطبيقات 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

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

يجب أن يتضمّن المشروع اعتمادية لمكتبة دعم Android المتوافقة مع MDC. من المفترض أنّ الرمز النموذجي الذي نزّلته يتضمّن هذه الاعتمادية، ولكن من الأفضل اتّباع الخطوات التالية للتأكّد من ذلك.

  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- إضافة شريط التطبيق العلوي

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

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

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

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

في الدالة 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.

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

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

249db074eff043f4.png

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

6. ملخّص

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

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

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

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

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

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

أريد مواصلة استخدام "مكوّنات Material" في المستقبل

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