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

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/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" لتثبيت هذه الحِزم أو تعديلها ومزامنة مشروعك.

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

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

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

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

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

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

إضافة بطاقة

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

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

أصبحت البطاقات متوفّرة الآن. لا تعرض هذه السمة أي معلومات بعد، لذا لنضِف بعض بيانات المنتجات.

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

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

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

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

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

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

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

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

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

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

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

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