MDC-101 Android: Material Components (MDC) Basic (Kotlin)

۱. مقدمه

logo_components_color_2x_web_96dp.png

کامپوننت‌های متریال (MDC) به توسعه‌دهندگان در پیاده‌سازی طراحی متریال کمک می‌کنند. MDC که توسط تیمی از مهندسان و طراحان UX در گوگل ایجاد شده است، ده‌ها کامپوننت رابط کاربری زیبا و کاربردی را ارائه می‌دهد و برای اندروید، iOS، وب و Flutter.material.io/develop در دسترس است.

طراحی متریال و کامپوننت‌های متریال برای اندروید چیستند؟

طراحی متریال سیستمی برای ساخت محصولات دیجیتال جسورانه و زیبا است. با متحد کردن سبک، برندسازی، تعامل و حرکت تحت مجموعه‌ای از اصول و اجزای سازگار، تیم‌های محصول می‌توانند به بزرگترین پتانسیل طراحی خود دست یابند.

برای برنامه‌های اندروید، کامپوننت‌های متریال برای اندروید ( MDC Android ) طراحی و مهندسی را با کتابخانه‌ای از کامپوننت‌ها برای ایجاد ثبات در سراسر برنامه شما متحد می‌کند. با تکامل سیستم طراحی متریال، این کامپوننت‌ها به‌روزرسانی می‌شوند تا پیاده‌سازی پیکسلی بی‌نقص و مطابق با استانداردهای توسعه front-end گوگل تضمین شود. MDC همچنین برای وب، iOS و Flutter در دسترس است.

در این آزمایشگاه کد، شما با استفاده از چندین کامپوننت اندروید MDC یک صفحه ورود خواهید ساخت.

آنچه خواهید ساخت

این آزمایشگاه کد، اولین از ۴ آزمایشگاه کد است که شما را در ساخت برنامه‌ای به نام Shrine ، یک برنامه اندروید تجارت الکترونیک که لباس و لوازم خانگی می‌فروشد، راهنمایی می‌کند. این آزمایشگاه نشان می‌دهد که چگونه می‌توانید با استفاده از MDC Android، اجزا را برای انعکاس هر برند یا سبکی سفارشی کنید.

در این آزمایشگاه کد، شما یک صفحه ورود برای Shrine خواهید ساخت که شامل موارد زیر است:

  • دو فیلد متنی، یکی برای وارد کردن نام کاربری و دیگری برای وارد کردن رمز عبور
  • دو دکمه، یکی برای «لغو» و دیگری برای «بعدی»
  • نام برنامه (معبد)
  • تصویری از لوگوی Shrine

4cb0c218948144b4.png

اجزای اندروید MDC در این آزمایشگاه کد

  • فیلد متنی
  • دکمه

آنچه نیاز دارید

  • دانش پایه در توسعه اندروید
  • اندروید استودیو (اگر ندارید، از اینجا دانلود کنید)
  • یک شبیه‌ساز یا دستگاه اندروید (از طریق اندروید استودیو قابل دسترسی است)
  • کد نمونه (به مرحله بعدی مراجعه کنید)

سطح تجربه خود در ساخت برنامه‌های اندروید را چگونه ارزیابی می‌کنید؟

تازه کار متوسط ماهر

۲. محیط توسعه خود را تنظیم کنید

راه اندازی اندروید استودیو

وقتی اندروید استودیو را باز می‌کنید، باید پنجره‌ای با عنوان "به اندروید استودیو خوش آمدید" نمایش داده شود. با این حال، اگر این اولین بار است که اندروید استودیو را اجرا می‌کنید، مراحل نصب اندروید استودیو را با مقادیر پیش‌فرض طی کنید. این مرحله می‌تواند چند دقیقه طول بکشد تا فایل‌های لازم دانلود و نصب شوند، بنابراین می‌توانید این مرحله را در پس‌زمینه اجرا کنید و بخش بعدی را انجام دهید.

اپلیکیشن استارتر codelab را دانلود کنید

برنامه‌ی آغازین در دایرکتوری material-components-android-codelabs-101-starter/kotlin قرار دارد.

... یا آن را از گیت‌هاب کلون کنید

برای کپی کردن این codelab از گیت‌هاب، دستورات زیر را اجرا کنید:

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

کد شروع را در اندروید استودیو بارگذاری کنید

  1. پس از اتمام مراحل نصب و نمایش پنجره Welcome to Android Studio ، روی Open an existing Android Studio project کلیک کنید. به پوشه‌ای که کد نمونه را در آن نصب کرده‌اید بروید و kotlin -> shrine را انتخاب کنید (یا در رایانه خود عبارت shrine را جستجو کنید) تا پروژه Shipping باز شود.
  2. لحظه‌ای صبر کنید تا اندروید استودیو پروژه را بسازد و همگام‌سازی کند، همانطور که توسط نشانگرهای فعالیت در پایین پنجره اندروید استودیو نشان داده شده است.
  3. در این مرحله، ممکن است اندروید استودیو به دلیل فقدان SDK اندروید یا ابزارهای ساخت، مانند آنچه در زیر نشان داده شده است، برخی خطاهای ساخت را ایجاد کند. برای نصب/به‌روزرسانی این موارد و همگام‌سازی پروژه خود، دستورالعمل‌های موجود در اندروید استودیو را دنبال کنید.

KzoYWC1S7Se7yL8igi1vXF_mbVxAdl2lg5kb7RODrsVpEng0G6U3NK1Qnn0faBBZd2u71yMXioy9tD-7fv3NXvVO4N3EtMMeWDTmqBMMl6egd9R5uXX0T_SKmahbmRor3wZZHX0ByA

اضافه کردن وابستگی‌های پروژه

این پروژه به یک وابستگی (dependency) در کتابخانه پشتیبانی اندروید 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. مطمئن شوید که پیکربندی ساخت در سمت چپ دکمه‌ی Run/Play برابر با app باشد.
  2. برای ساخت و اجرای برنامه، دکمه سبز اجرا / پخش (Run / Play) را فشار دهید.
  3. در پنجره Select Deployment Target ، اگر از قبل یک دستگاه اندروید در فهرست دستگاه‌های موجود خود دارید، به مرحله ۸ بروید. در غیر این صورت، روی Create New Virtual Device کلیک کنید.
  4. در صفحه انتخاب سخت‌افزار ، یک دستگاه تلفن مانند Pixel 2 را انتخاب کنید و سپس روی Next کلیک کنید.
  5. در صفحه System Image ، یک نسخه جدید اندروید ، ترجیحاً بالاترین سطح API، را انتخاب کنید. اگر نصب نشده است، روی لینک دانلود نمایش داده شده کلیک کنید و دانلود را تکمیل کنید.
  6. روی بعدی کلیک کنید.
  7. در صفحه دستگاه مجازی اندروید (AVD) ، تنظیمات را همانطور که هستند رها کنید و روی Finish کلیک کنید.
  8. یک دستگاه اندروید را از کادر محاوره‌ای هدف استقرار انتخاب کنید.
  9. روی تأیید کلیک کنید.
  10. اندروید استودیو برنامه را می‌سازد، آن را مستقر می‌کند و به طور خودکار آن را روی دستگاه هدف باز می‌کند.

موفقیت! کد آغازین برای صفحه ورود به Shrine باید در شبیه‌ساز شما اجرا شود. باید نام "Shrine" و لوگوی Shrine را درست در زیر آن ببینید.

e7ed014e84755811.png

بیایید نگاهی به کد بیندازیم. ما در کد نمونه خود یک چارچوب ناوبری ساده Fragment برای نمایش Fragmentها و پیمایش بین Fragmentها ارائه داده‌ایم.

MainActivity.kt در مسیر shrine -> app -> src -> main -> java -> com.google.codelabs.mdc.kotlin.shrine باز کنید. این فایل باید شامل موارد زیر باشد:

فعالیت اصلی.kt

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

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment

class MainActivity : AppCompatActivity(), NavigationHost {

   override fun onCreate(savedInstanceState: Bundle?) {
       super.onCreate(savedInstanceState)
       setContentView(R.layout.shr_main_activity)

       if (savedInstanceState == null) {
           supportFragmentManager
                   .beginTransaction()
                   .add(R.id.container, LoginFragment())
                   .commit()
       }
   }

   override fun navigateTo(fragment: Fragment, addToBackstack: Boolean) {
       val transaction = supportFragmentManager
               .beginTransaction()
               .replace(R.id.container, fragment)

       if (addToBackstack) {
           transaction.addToBackStack(null)
       }

       transaction.commit()
   }
}

این فعالیت، فایل طرح‌بندی R.layout.shr_main_activity را که در shr_main_activity.xml تعریف شده است، نمایش می‌دهد.

می‌توانید ببینید که در onCreate(), MainActivity.kt یک تراکنش Fragment را برای نمایش LoginFragment آغاز می‌کند. برای این کد، ما LoginFragment تغییر خواهیم داد. این اکتیویتی همچنین یک متد navigateTo(Fragment) را پیاده‌سازی می‌کند که در NavigationHost تعریف شده است و به هر fragment اجازه می‌دهد تا به fragment دیگری هدایت شود.

برای باز کردن فایل طرح‌بندی، در فایل activity، کلیدهای Command + Click (یا Control + Click ) را فشار دهید تا فایل طرح‌بندی shr_main_activity باز شود، یا از طریق app -> res -> layout -> shr_main_activity.xml به فایل طرح‌بندی بروید.

shr_main_activity.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:tools="http://schemas.android.com/tools"
   android:id="@+id/container"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   tools:context=".MainActivity"/>

در اینجا، یک <FrameLayout> ساده می‌بینیم که به عنوان یک ظرف برای هر قطعه‌ای که اکتیویتی نمایش می‌دهد، عمل می‌کند.

در مرحله بعد، بیایید LoginFragment.kt باز کنیم.

ورودFragment.kt

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

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment

class LoginFragment : Fragment() {

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

       return view
   }
}

LoginFragment فایل طرح‌بندی shr_login_fragment را inflate کرده و آن را در onCreateView() نمایش می‌دهد.

حالا، بیایید نگاهی به فایل طرح‌بندی shr_login_fragment.xml بیندازیم تا ببینیم صفحه ورود چگونه به نظر می‌رسد.

shr_login_fragment.xml

<?xml version="1.0" encoding="utf-8"?>
<ScrollView 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"
   android:background="@color/loginPageBackgroundColor"
   tools:context=".LoginFragment">

   <LinearLayout
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:clipChildren="false"
       android:clipToPadding="false"
       android:orientation="vertical"
       android:padding="24dp"
       android:paddingTop="16dp">

       <ImageView
           android:layout_width="64dp"
           android:layout_height="64dp"
           android:layout_gravity="center_horizontal"
           android:layout_marginTop="48dp"
           android:layout_marginBottom="16dp"
           app:srcCompat="@drawable/shr_logo" />

       <TextView
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:layout_gravity="center_horizontal"
           android:layout_marginBottom="132dp"
           android:text="@string/shr_app_name"
           android:textAllCaps="true"
           android:textSize="16sp" />
   </LinearLayout>
</ScrollView>

در اینجا، می‌توانیم یک <LinearLayout> با یک <ImageView> در بالا ببینیم که نشان‌دهنده‌ی لوگوی Shrine است.

پس از آن، یک تگ <TextView> وجود دارد که نشان دهنده برچسب Shrine در زیر لوگو است. متن این برچسب یک منبع رشته‌ای با نام @string/shr_app_name است. اگر نام منبع رشته‌ای را با کلیدهای Command + Click (یا Control + Click ) فشار دهید، یا app -> res -> values -> strings.xml را باز کنید، می‌توانید فایل strings.xml را که منابع رشته‌ای در آن تعریف شده‌اند، مشاهده کنید. وقتی منابع رشته‌ای بیشتری در آینده اضافه شوند، در اینجا تعریف خواهند شد. هر منبعی در این فایل باید یک پیشوند shr_ داشته باشد تا نشان دهد که بخشی از برنامه Shrine است.

حالا که با کد اولیه آشنا شدید، بیایید اولین کامپوننت خود را پیاده‌سازی کنیم.

۳. فیلدهای متنی اضافه کنید

برای شروع، دو فیلد متنی به صفحه ورود خود اضافه خواهیم کرد تا افراد بتوانند نام کاربری و رمز عبور خود را وارد کنند. ما از کامپوننت MDC Text Field استفاده خواهیم کرد که شامل قابلیت‌های داخلی نمایش برچسب شناور و پیام‌های خطا است.

d83c47fb4aed3a82.png

XML را اضافه کنید

در shr_login_fragment.xml ، دو عنصر TextInputLayout با یک عنصر فرزند TextInputEditText درون <LinearLayout> و زیر برچسب "SHRINE" یعنی <TextView> اضافه کنید:

shr_login_fragment.xml

<com.google.android.material.textfield.TextInputLayout
   android:layout_width="match_parent"
   android:layout_height="wrap_content"
   android:layout_margin="4dp"
   android:hint="@string/shr_hint_username">

   <com.google.android.material.textfield.TextInputEditText
       android:layout_width="match_parent"
       android:layout_height="wrap_content" />
</com.google.android.material.textfield.TextInputLayout>

<com.google.android.material.textfield.TextInputLayout
   android:id="@+id/password_text_input"
   android:layout_width="match_parent"
   android:layout_height="wrap_content"
   android:layout_margin="4dp"
   android:hint="@string/shr_hint_password">

   <com.google.android.material.textfield.TextInputEditText
       android:id="@+id/password_edit_text"
       android:layout_width="match_parent"
       android:layout_height="wrap_content" />
</com.google.android.material.textfield.TextInputLayout>

قطعه کد بالا دو فیلد متنی را نشان می‌دهد که هر کدام شامل یک عنصر <TextInputLayout> و یک فرزند <TextInputEditText> هستند. متن راهنما برای هر فیلد متنی در ویژگی android:hint مشخص شده است.

ما دو منبع رشته‌ای جدید برای فیلد متن اضافه کرده‌ایم - @string/shr_hint_username و @string/shr_hint_password . برای مشاهده این منابع رشته‌ای، strings.xml را باز کنید.

رشته‌ها.xml

<string name="shr_hint_username">Username</string>
<string name="shr_hint_password">Password</string>

اعتبارسنجی ورودی را اضافه کنید

کامپوننت‌های TextInputLayout قابلیت بازخورد خطا را به صورت داخلی ارائه می‌دهند.

برای نمایش بازخورد خطا، تغییرات زیر را در shr_login_fragment.xml اعمال کنید:

  • ویژگی app:errorEnabled را در عنصر Password TextInputLayout روی true تنظیم کنید. این کار باعث می‌شود که برای پیام خطا در زیر فیلد متن، حاشیه اضافی اضافه شود.
  • ویژگی android:inputType در عنصر Password TextInputEditText برابر با " textPassword " قرار دهید. این کار متن ورودی را در فیلد رمز عبور پنهان می‌کند.

با این تغییرات، فیلدهای متنی در shr_login_fragment.xml باید به شکل زیر باشند:

shr_login_fragment.xml

<com.google.android.material.textfield.TextInputLayout
   android:layout_width="match_parent"
   android:layout_height="wrap_content"
   android:layout_margin="4dp"
   android:hint="@string/shr_hint_username">

   <com.google.android.material.textfield.TextInputEditText
       android:layout_width="match_parent"
       android:layout_height="wrap_content" />
</com.google.android.material.textfield.TextInputLayout>

<com.google.android.material.textfield.TextInputLayout
   android:id="@+id/password_text_input"
   android:layout_width="match_parent"
   android:layout_height="wrap_content"
   android:layout_margin="4dp"
   android:hint="@string/shr_hint_password"
   app:errorEnabled="true">

   <com.google.android.material.textfield.TextInputEditText
       android:id="@+id/password_edit_text"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:inputType="textPassword" />
</com.google.android.material.textfield.TextInputLayout>

حالا برنامه را اجرا کنید. باید صفحه‌ای با دو فیلد متنی برای «نام کاربری» و «رمز عبور» ببینید!

انیمیشن برچسب شناور را ببینید:

333184b615aed4f7.gif

۴. دکمه‌ها را اضافه کنید

در مرحله بعد، دو دکمه به صفحه ورود خود اضافه خواهیم کرد: «لغو» و «بعدی». ما از کامپوننت دکمه MDC استفاده خواهیم کرد که دارای جلوه موجی جوهر Material Design است.

4cb0c218948144b4.png

XML را اضافه کنید

در shr_login_fragment.xml ، یک <RelativeLayout> به <LinearLayout> ، زیر عناصر TextInputLayout اضافه کنید. سپس دو عنصر <MaterialButton> را به <RelativeLayout> اضافه کنید.

فایل XML حاصل باید به شکل زیر باشد:

shr_login_fragment.xml

<RelativeLayout
   android:layout_width="match_parent"
   android:layout_height="wrap_content">

   <com.google.android.material.button.MaterialButton
       android:id="@+id/next_button"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:layout_alignParentEnd="true"
       android:layout_alignParentRight="true"
       android:text="@string/shr_button_next" />

   <com.google.android.material.button.MaterialButton
       android:id="@+id/cancel_button"
       style="@style/Widget.MaterialComponents.Button.TextButton"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:layout_marginEnd="12dp"
       android:layout_marginRight="12dp"
       android:layout_toStartOf="@id/next_button"
       android:layout_toLeftOf="@id/next_button"
       android:text="@string/shr_button_cancel" />

</RelativeLayout>

همین! وقتی برنامه را اجرا می‌کنید، با لمس هر دکمه، موجی از جوهر نمایش داده می‌شود.

9dd162d65e4a92a2.gif

۵. رفتن به قطعه بعدی

در نهایت، مقداری کد کاتلین به LoginFragment.kt اضافه می‌کنیم تا دکمه "NEXT" را برای انتقال به یک قطعه کد دیگر متصل کنیم.

بیایید یک متد خصوصی از نوع بولی به نام isPasswordValid در LoginFragment.kt زیر onCreateView() اضافه کنیم، با منطقی که تعیین کند رمز عبور معتبر است یا خیر. برای اهداف این نسخه آزمایشی، فقط مطمئن می‌شویم که رمز عبور حداقل ۸ کاراکتر داشته باشد:

ورودFragment.kt

private fun isPasswordValid(text: Editable?): Boolean {
   return text != null && text.length >= 8
}

در مرحله بعد، یک شنونده کلیک به دکمه "Next" اضافه کنید که خطا را بر اساس متد isPasswordValid() که تازه ایجاد کرده‌ایم، تنظیم و پاک می‌کند. در onCreateView() ، این شنونده کلیک باید بین خط inflater و خط return view قرار گیرد.

حالا بیایید یک شنونده‌ی کلید به TextInputEditText رمز عبور اضافه کنیم تا رویدادهای کلیدی که خطا را برطرف می‌کنند را بررسی کند. این شنونده همچنین باید isPasswordValid() برای بررسی معتبر بودن یا نبودن رمز عبور استفاده کند. می‌توانید این را مستقیماً زیر شنونده‌ی کلیک در onCreateView() اضافه کنید.

متد onCreateView() شما اکنون باید چیزی شبیه به این باشد:

ورودFragment.kt

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

       // Set an error if the password is less than 8 characters.
       view.next_button.setOnClickListener({
           if (!isPasswordValid(password_edit_text.text!!)) {
               password_text_input.error = getString(R.string.shr_error_password)
           } else {
               // Clear the error.
               password_text_input.error = null
           }
       })

       // Clear the error once more than 8 characters are typed.
       view.password_edit_text.setOnKeyListener({ _, _, _ ->
           if (isPasswordValid(password_edit_text.text!!)) {
               // Clear the error.
               password_text_input.error = null
           }
           false
       })

       return view
   }
}

حالا می‌توانیم به یک قطعه کد دیگر برویم. در onCreateView() ، تابع OnClickListener را به‌روزرسانی کنید تا وقتی اعتبارسنجی خطا با موفقیت انجام شد، به قطعه کد دیگری برویم. کد clickListener شما اکنون باید به شکل زیر باشد:

ورودFragment.kt

// Set an error if the password is less than 8 characters.
view.next_button.setOnClickListener({
   if (!isPasswordValid(password_edit_text.text!!)) {
       password_text_input.error = getString(R.string.shr_error_password)
   } else {
       // Clear the error.
       password_text_input.error = null
       // Navigate to the next Fragment.
       (activity as NavigationHost).navigateTo(ProductGridFragment(), false)
   }
})

ما خط ( activity as NavigationHost).navigateTo(ProductGridFragment(), false ) ‎ را به حالت else از شنونده کلیک اضافه کرده‌ایم. این خط، متد navigateTo() را از MainActivity برای پیمایش به یک قطعه جدید - ProductGridFragment - فراخوانی می‌کند. در حال حاضر، این یک صفحه خالی است که در MDC-102 روی آن کار خواهید کرد.

حالا، برنامه را بسازید. ادامه دهید و دکمه Next را بزنید.

موفق شدی! این صفحه، نقطه شروع آزمایشگاه کد بعدی ما خواهد بود که در MDC-102 روی آن کار خواهی کرد.

۶. همه چیز انجام شد

کتابخانه Material Components for Android با استفاده از نشانه‌گذاری XML پایه و حدود ۳۰ خط کد کاتلین، به شما کمک کرده است تا یک صفحه ورود زیبا ایجاد کنید که با دستورالعمل‌های طراحی متریال مطابقت داشته باشد و همچنین در همه دستگاه‌ها به طور یکسان ظاهر و رفتار کند.

مراحل بعدی

فیلد متنی و دکمه دو کامپوننت اصلی در کتابخانه اندروید MDC هستند، اما کامپوننت‌های بسیار بیشتری وجود دارد! می‌توانید بقیه کامپوننت‌ها را در MDC Android بررسی کنید. همچنین، می‌توانید به MDC 102: ساختار و چیدمان طراحی متریال مراجعه کنید تا در مورد نوار بالای برنامه، نمای کارت و چیدمان شبکه‌ای اطلاعات کسب کنید. از تلاش شما برای استفاده از کامپوننت‌های متریال متشکریم. امیدواریم از این آزمایشگاه کد لذت برده باشید!

من توانستم این آزمایشگاه کد را با مقدار قابل توجهی از زمان و تلاش تکمیل کنم.

کاملاً موافقم موافق خنثی مخالف کاملاً مخالفم

من دوست دارم در آینده به استفاده از کامپوننت‌های متریال ادامه دهم.

کاملاً موافقم موافق خنثی مخالف کاملاً مخالفم