MDC-102 Android: структура и макет материала (Kotlin)

1. Введение

logo_comComponents_color_2x_web_96dp.png

Material Components (MDC) помогают разработчикам реализовать Material Design. MDC, созданный командой инженеров и UX-дизайнеров Google, включает в себя десятки красивых и функциональных компонентов пользовательского интерфейса и доступен для Android, iOS, Интернета и Flutter.material.io/develop.

В кодовой лаборатории MDC-101 вы использовали два компонента материала (MDC) для создания страницы входа в систему: текстовые поля и кнопки с чернильной рябью. Теперь давайте расширим эту основу, добавив навигацию, структуру и данные.

Что ты построишь

В этой лаборатории кода вы создадите главный экран для приложения Shrine — приложения для электронной коммерции, которое продает одежду и товары для дома. Он будет содержать:

  • Верхняя панель приложений
  • Сетчатый список, полный продуктов

249db074eff043f4.png

Компоненты MDC-Android в этой лаборатории кода

  • AppBarLayout
  • МатериалКартаView

Что вам понадобится

  • Базовые знания Android-разработки.
  • Android Studio (скачайте здесь , если у вас его еще нет)
  • Эмулятор Android или устройство (доступно через Android Studio).
  • Пример кода (см. следующий шаг)

Как бы вы оценили свой опыт создания приложений для Android?

Новичок Средний Опытный

2. Настройте среду разработки

Продолжаем MDC-101?

Если вы прошли MDC-101, ваш код должен быть подготовлен для этой лаборатории. Перейдите к шагу 3. Добавьте верхнюю панель приложения .

Начиная с нуля?

Загрузите начальное приложение Codelab.

Стартовое приложение находится в каталоге 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 Studio.

  1. После завершения работы мастера установки и появления окна «Добро пожаловать в Android Studio» нажмите « Открыть существующий проект Android Studio» . Перейдите в каталог, в который вы установили пример кода, и выберите kotlin -> shrine (или найдите на своем компьютере shrine ), чтобы открыть проект Shipping.
  2. Подождите, пока Android Studio создаст и синхронизирует проект, как показывают индикаторы активности в нижней части окна Android Studio.
  3. На этом этапе Android Studio может вызвать некоторые ошибки сборки, поскольку вам не хватает Android SDK или инструментов сборки, таких как показанный ниже. Следуйте инструкциям в Android Studio, чтобы установить/обновить их и синхронизировать проект.

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 , желательно самого высокого уровня API. Если он не установлен, щелкните появившуюся ссылку «Загрузить» и завершите загрузку.
  6. Нажмите Далее .
  7. На экране виртуального устройства Android (AVD) оставьте настройки без изменений и нажмите « Готово» .
  8. Выберите устройство Android в диалоговом окне цели развертывания.
  9. Нажмите «ОК» .
  10. Android Studio создает приложение, развертывает его и автоматически открывает на целевом устройстве.

Успех! Вы должны увидеть страницу входа в Shrine из лаборатории кода MDC-101.

4cb0c218948144b4.png

Теперь, когда экран входа в систему выглядит хорошо, давайте добавим в приложение несколько продуктов.

3. Добавьте верхнюю панель приложений.

Когда закрывается страница входа в систему, открывается главный экран с надписью «Вы сделали это!». Замечательно! Но теперь у нашего пользователя нет никаких действий или никакого представления о том, где он находится в приложении. Чтобы помочь в этом, пришло время добавить навигацию.

Material Design предлагает шаблоны навигации, которые обеспечивают высокую степень удобства использования. Одним из наиболее заметных компонентов является верхняя панель приложений.

Чтобы обеспечить навигацию и предоставить пользователям быстрый доступ к другим действиям, давайте добавим верхнюю панель приложения.

Добавьте виджет AppBar

В shr_product_grid_fragment.xml удалите блок <LinearLayout> , содержащий надпись «Вы сделали это!» TextView и замените его следующим:

shr_product_grid_fragment.xml

<com.google.android.material.appbar.AppBarLayout
   android:layout_width="match_parent"
   android:layout_height="wrap_content">

   <androidx.appcompat.widget.Toolbar
       android:id="@+id/app_bar"
       style="@style/Widget.Shrine.Toolbar"
       android:layout_width="match_parent"
       android:layout_height="?attr/actionBarSize"
       app:title="@string/shr_app_name" />
</com.google.android.material.appbar.AppBarLayout>

Ваш shr_product_grid_fragment.xml теперь должен выглядеть следующим образом:

shr_product_grid_fragment.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:app="http://schemas.android.com/apk/res-auto"
   xmlns:tools="http://schemas.android.com/tools"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   tools:context=".ProductGridFragment">

   <com.google.android.material.appbar.AppBarLayout
       android:layout_width="match_parent"
       android:layout_height="wrap_content">

       <androidx.appcompat.widget.Toolbar
           android:id="@+id/app_bar"
           style="@style/Widget.Shrine.Toolbar"
           android:layout_width="match_parent"
           android:layout_height="?attr/actionBarSize"
           app:title="@string/shr_app_name" />
   </com.google.android.material.appbar.AppBarLayout>
  
</FrameLayout>

На многих панелях приложений есть кнопка рядом с заголовком. Давайте добавим иконку меню в нашу.

Добавьте значок навигации

Находясь в shr_product_grid_fragment.xml , добавьте следующее к XML-компоненту Toolbar , который вы только что добавили в свой макет:

shr_product_grid_fragment.xml

app:navigationIcon="@drawable/shr_menu"

Ваш shr_product_grid_fragment.xml должен выглядеть следующим образом:

shr_product_grid_fragment.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:app="http://schemas.android.com/apk/res-auto"
   xmlns:tools="http://schemas.android.com/tools"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   tools:context=".ProductGridFragment">
  
   <com.google.android.material.appbar.AppBarLayout
       android:layout_width="match_parent"
       android:layout_height="wrap_content">

       <androidx.appcompat.widget.Toolbar
           android:id="@+id/app_bar"
           style="@style/Widget.Shrine.Toolbar"
           android:layout_width="match_parent"
           android:layout_height="?attr/actionBarSize"
           app:navigationIcon="@drawable/shr_menu"
           app:title="@string/shr_app_name" />
   </com.google.android.material.appbar.AppBarLayout>
  
</FrameLayout>

Добавьте кнопки действий и стиль верхней панели приложений.

Вы также можете добавить кнопки в конце панели приложения. В Android они называются кнопками действий . Мы оформим верхнюю панель приложения и программно добавим кнопки действий в ее меню.

В функции 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 . В этом классе хранятся представления, влияющие на макет нашей карточки, поэтому мы можем изменить их позже.

ПродуктCardViewHolder.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 под XML-компонентом AppBarLayout :

shr_product_grid_fragment.xml

<androidx.core.widget.NestedScrollView
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   android:layout_marginTop="56dp"
   android:background="@color/productGridBackgroundColor"
   android:paddingStart="@dimen/shr_product_grid_spacing"
   android:paddingEnd="@dimen/shr_product_grid_spacing"
   app:layout_behavior="@string/appbar_scrolling_view_behavior">

   <androidx.recyclerview.widget.RecyclerView
       android:id="@+id/recycler_view"
       android:layout_width="match_parent"
       android:layout_height="match_parent" />

</androidx.core.widget.NestedScrollView>

Ваш shr_product_grid_fragment.xml должен выглядеть следующим образом:

shr_product_grid_fragment.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:app="http://schemas.android.com/apk/res-auto"
   xmlns:tools="http://schemas.android.com/tools"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   tools:context=".ProductGridFragment">

   <com.google.android.material.appbar.AppBarLayout
       android:layout_width="match_parent"
       android:layout_height="wrap_content">

       <androidx.appcompat.widget.Toolbar
           android:id="@+id/app_bar"
           style="@style/Widget.Shrine.Toolbar"
           android:layout_width="match_parent"
           android:layout_height="?attr/actionBarSize"
           app:navigationIcon="@drawable/shr_menu"
           app:title="@string/shr_app_name" />
   </com.google.android.material.appbar.AppBarLayout>

   <androidx.core.widget.NestedScrollView
       android:layout_width="match_parent"
       android:layout_height="match_parent"
       android:layout_marginTop="56dp"
       android:background="@color/productGridBackgroundColor"
       android:paddingStart="@dimen/shr_product_grid_spacing"
       android:paddingEnd="@dimen/shr_product_grid_spacing"
       app:layout_behavior="@string/appbar_scrolling_view_behavior">

       <androidx.recyclerview.widget.RecyclerView
           android:id="@+id/recycler_view"
           android:layout_width="match_parent"
           android:layout_height="match_parent" />

   </androidx.core.widget.NestedScrollView>

</FrameLayout>

Наконец, в onCreateView() добавьте код инициализации RecyclerView в ProductGridFragment.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 теперь должен выглядеть следующим образом:

Продуктгридфрагмент .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 добавьте три представления следующим образом.

ПродуктCardViewHolder.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 в будущем.

Полностью согласен Соглашаться Нейтральный Не согласен Категорически не согласен