1. Введение
Компоненты Material (MDC) помогают разработчикам внедрять Material Design. Созданные командой инженеров и UX-дизайнеров Google, MDC включают в себя десятки красивых и функциональных компонентов пользовательского интерфейса и доступны для Android, iOS, веб-приложений и Flutter.material.io/develop |
В практическом занятии MDC-101 вы использовали два компонента Material Components (MDC) для создания страницы входа в систему: текстовые поля и кнопки с эффектом чернильной ряби. Теперь давайте расширим эту основу, добавив навигацию, структуру и данные.
Что вы построите
В этом практическом занятии вы создадите главный экран для приложения Shrine , приложения электронной коммерции, продающего одежду и товары для дома. Он будет содержать:
- Панель приложений верхнего уровня
- Список товаров в виде сетки

Компоненты MDC-Android в этом практическом занятии.
- AppBarLayout
- MaterialCardView
Что вам понадобится
- Базовые знания разработки под 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.
- После завершения работы мастера установки и появления окна «Добро пожаловать в Android Studio» нажмите « Открыть существующий проект Android Studio» . Перейдите в каталог, где вы установили примеры кода, и выберите kotlin -> shrine (или найдите shrine на своем компьютере), чтобы открыть проект Shipping.
- Подождите немного, пока Android Studio соберет и синхронизирует проект, как это отобразится в индикаторах активности в нижней части окна Android Studio.
- На этом этапе Android Studio может выдавать ошибки сборки, поскольку у вас отсутствует Android SDK или инструменты сборки, например, показанные ниже. Следуйте инструкциям в Android Studio, чтобы установить/обновить их и синхронизировать ваш проект.
Добавьте зависимости проекта
Проекту необходима зависимость от библиотеки поддержки Android MDC . В загруженном вами примере кода эта зависимость уже должна быть указана, но для уверенности рекомендуется выполнить следующие шаги.
- Перейдите к файлу
build.gradleмодуляappи убедитесь, что блокdependenciesвключает зависимость от MDC Android:
api 'com.google.android.material:material:1.1.0-alpha06'
- (Необязательно) При необходимости отредактируйте файл
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'
}
Запустите стартовое приложение
|
Успех! Вы должны увидеть страницу входа в Shrine из практического занятия MDC-101.

Теперь, когда экран входа в систему выглядит хорошо, давайте добавим в приложение несколько товаров.
3. Добавьте верхнюю панель приложений.
Главный экран появляется после закрытия страницы входа, и на нем отображается надпись «Вы это сделали!». Отлично! Но теперь пользователю не нужно ничего делать, и он не понимает, где находится в приложении. Чтобы решить эту проблему, пора добавить навигацию.
Material Design предлагает шаблоны навигации, обеспечивающие высокую степень удобства использования. Одним из наиболее заметных компонентов является верхняя панель приложений.
Для обеспечения навигации и быстрого доступа пользователей к другим действиям добавим верхнюю панель приложения.
Добавьте виджет AppBar
В TextView shr_product_grid_fragment.xml удалите блок <LinearLayout> , содержащий текстовое поле "You did it!", и замените его следующим:
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)
}
}
Соберите и запустите. Ваш главный экран должен выглядеть примерно так:

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

На этом предварительном просмотре вы можете увидеть, что карточка отстоит от левого края, имеет закругленные углы и тень (которая подчеркивает возвышение карточки). Весь элемент называется «контейнером». За исключением контейнера, все элементы внутри него являются необязательными.
В контейнер можно добавить следующие элементы: заголовок, миниатюру или аватар, подзаголовок, разделители и даже кнопки и значки. Например, созданная нами карточка содержит два элемента 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 . Этот класс хранит представления, влияющие на макет карточки, поэтому мы можем изменить их позже.
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 .
Здесь текстовые данные устанавливаются в каждом из TextView элементов ViewHolder , а для получения изображения по URL-адресу вызывается ImageRequester . Класс ImageRequester предоставлен нами для вашего удобства и использует библиотеку Volley (это тема, выходящая за рамки данного практического занятия, но вы можете изучить код самостоятельно).
Соберите и запустите:

Наши товары теперь отображаются в приложении!
6. Подведение итогов
Наше приложение имеет простую структуру, которая ведет пользователя от экрана входа в систему к главному экрану, где можно просматривать товары. Всего несколькими строками кода мы добавили верхнюю панель приложения с заголовком и тремя кнопками, а также сетку карточек для отображения контента приложения. Теперь наш главный экран прост и функционален, имеет базовую структуру и содержит интерактивный контент.
Следующие шаги
Для верхней панели приложения, карточки, текстового поля и кнопки мы использовали четыре основных компонента Material Design из библиотеки MDC-Android! Вы можете ознакомиться с еще большим количеством компонентов, посетив каталог MDC-Android.
Хотя наше приложение полностью функционально, оно пока не отражает какой-либо конкретный бренд или стиль. В курсе MDC-103: Тематическое оформление в стиле Material Design с использованием цвета, формы, рельефа и шрифта , мы настроим стиль этих компонентов, чтобы выразить яркий, современный бренд.
