MDC-102 Android: struktura i układ materiału (Kotlin)

logo_components_color_2x_web_96dp.png

Komponenty Material (MDC) pomagają deweloperom wdrażać Material Design. MDC to stworzona przez zespół inżynierów i projektantów UX z Google biblioteka zawierająca dziesiątki atrakcyjnych i funkcjonalnych komponentów interfejsu. Jest dostępna na platformy Android, iOS, internet i Flutter.

material.io/develop

W kursie MDC-101 do utworzenia strony logowania użyto 2 komponentów Material Design: pól tekstowych i przycisków z efektem rozchodzenia się fali. Teraz rozbudujmy tę podstawę, dodając nawigację, strukturę i dane.

Co utworzysz

W tym laboratorium kodowania utworzysz ekran główny aplikacji Shrine, czyli aplikacji do handlu elektronicznego, w której sprzedawane są ubrania i artykuły gospodarstwa domowego. Będzie ona zawierać:

  • Górny pasek aplikacji
  • Lista produktów w formie siatki

Komponenty MDC-Android w tym kursie

  • AppBarLayout
  • MaterialCardView

Czego potrzebujesz

  • Podstawowa wiedza na temat programowania aplikacji na Androida
  • Android Studio (jeśli nie masz jeszcze tego środowiska, pobierz je tutaj)
  • emulator lub urządzenie z Androidem (dostępne w Android Studio);
  • Przykładowy kod (patrz następny krok)

Jak oceniasz swoje doświadczenie w tworzeniu aplikacji na Androida?

Początkujący Średnio zaawansowany Zaawansowany

Kontynuujesz naukę z MDC-101?

Jeśli masz już za sobą MDC-101, Twój kod powinien być gotowy do tego ćwiczenia. Przejdź do kroku 3: Dodaj górny pasek aplikacji.

Zaczynasz od zera?

Pobieranie aplikacji do ćwiczeń z programowania

Pobierz aplikację startową

Aplikacja startowa znajduje się w katalogu material-components-android-codelabs-102-starter/kotlin. Zanim zaczniesz, cd do tego katalogu.

...lub sklonuj go z GitHub

Aby sklonować ten codelab z GitHuba, uruchom te polecenia:

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

Wczytaj kod startowy w Android Studio

  1. Gdy kreator konfiguracji zakończy działanie i wyświetli się okno Witamy w Android Studio, kliknij Otwórz istniejący projekt Android Studio. Przejdź do katalogu, w którym został zainstalowany przykładowy kod, i wybierz kotlin –> shrine(lub wyszukaj na komputerze shrine), aby otworzyć projekt Shipping.
  2. Poczekaj chwilę, aż Android Studio utworzy i zsynchronizuje projekt. Wskaźniki aktywności w dolnej części okna Android Studio będą pokazywać postęp.
  3. W tym momencie Android Studio może zgłosić błędy kompilacji, ponieważ brakuje Ci pakietu SDK Androida lub narzędzi do kompilacji, np. takich jak te pokazane poniżej. Postępuj zgodnie z instrukcjami w Android Studio, aby zainstalować lub zaktualizować te komponenty i zsynchronizować projekt.

Dodawanie zależności projektu

Projekt musi być zależny od biblioteki pomocy MDC na Androida. Pobrany przykładowy kod powinien już zawierać tę zależność, ale warto wykonać poniższe czynności, aby się upewnić.

  1. Otwórz plik build.gradle modułu app i upewnij się, że blok dependencies zawiera zależność od MDC Android:
api 'com.google.android.material:material:1.1.0-alpha06'
  1. (Opcjonalnie) W razie potrzeby edytuj plik build.gradle, aby dodać te zależności, i zsynchronizuj projekt.
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'
}

Uruchom aplikację startową

  1. Sprawdź, czy konfiguracja kompilacji po lewej stronie przycisku Uruchom / Odtwórz to app.
  2. Naciśnij zielony przycisk Uruchom / Odtwórz, aby skompilować i uruchomić aplikację.
  3. Jeśli w oknie Wybierz miejsce wdrożenia na liście dostępnych urządzeń widzisz już urządzenie z Androidem, przejdź do kroku 8. W przeciwnym razie kliknij Utwórz nowe urządzenie wirtualne.
  4. Na ekranie Wybierz sprzęt wybierz telefon, np. Pixel 2, a potem kliknij Dalej.
  5. Na ekranie Obraz systemu wybierz najnowszą wersję Androida, najlepiej z najwyższym poziomem interfejsu API. Jeśli nie jest zainstalowana, kliknij wyświetlony link Pobierz i dokończ pobieranie.
  6. Kliknij Dalej.
  7. Na ekranie Android Virtual Device (AVD) pozostaw ustawienia bez zmian i kliknij Finish (Zakończ).
  8. W oknie docelowym wdrożenia wybierz urządzenie z Androidem.
  9. Kliknij OK.
  10. Android Studio skompiluje aplikację, wdroży ją i automatycznie otworzy na urządzeniu docelowym.

Gotowe! Powinna wyświetlić się strona logowania Shrine z ćwiczenia MDC-101.

Ekran logowania wygląda już dobrze, więc teraz wypełnimy aplikację produktami.

Po zamknięciu strony logowania wyświetli się ekran główny z komunikatem „Udało Ci się!”. Wspaniale. Ale teraz użytkownik nie może podjąć żadnych działań ani nie wie, gdzie znajduje się w aplikacji. Aby mu w tym pomóc, dodajmy nawigację.

Material Design oferuje wzorce nawigacji, które zapewniają wysoki poziom użyteczności. Jednym z najbardziej widocznych elementów jest górny pasek aplikacji.

Aby zapewnić nawigację i umożliwić użytkownikom szybki dostęp do innych działań, dodajmy górny pasek aplikacji.

Dodawanie widżetu AppBar

W shr_product_grid_fragment.xml usuń blok <LinearLayout> zawierający tekst „Udało Ci się!”. TextView i zastąp go tym tekstem:

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>

Plik shr_product_grid_fragment.xml powinien teraz wyglądać tak:

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>

Wiele pasków aplikacji ma przycisk obok tytułu. Dodajmy do niego ikonę menu.

Dodawanie ikony nawigacji

shr_product_grid_fragment.xml dodaj do komponentu Toolbar XML, który został właśnie dodany do układu, te elementy:

shr_product_grid_fragment.xml

app:navigationIcon="@drawable/shr_menu"

Plik shr_product_grid_fragment.xml powinien wyglądać tak:

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>

Dodawanie przycisków działań i stylizowanie górnego paska aplikacji

Możesz też dodać przyciski po prawej stronie paska aplikacji. Na urządzeniach z Androidem są one nazywane przyciskami działania. Programowo nadamy styl górnemu paskowi aplikacji i dodamy do jego menu przyciski działań.

W funkcji ProductGridFragment.kt onCreateView ustaw activity Toolbar, które mają być używane jako ActionBar, za pomocą setSupportActionBar. Możesz to zrobić po utworzeniu widoku za pomocą ikony 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;
}

Następnie bezpośrednio pod metodą, którą właśnie zmieniliśmy, aby skonfigurować pasek narzędzi, zastąpmy onCreateOptionsMenu, aby wstawić zawartość shr_toolbar_menu.xml na pasek narzędzi:

ProductGridFragment.kt

override fun onCreateOptionsMenu(menu: Menu, menuInflater: MenuInflater) {
   menuInflater.inflate(R.menu.shr_toolbar_menu, menu)
   super.onCreateOptionsMenu(menu, menuInflater)
}

Na koniec zastąp onCreate()ProductGridFragment.kt, a po wywołaniu super() wywołaj setHasOptionMenutrue:

ProductGridFragment.kt

override fun onCreate(savedInstanceState: Bundle?) {
   super.onCreate(savedInstanceState)
   setHasOptionsMenu(true)
}

Powyższe fragmenty kodu ustawiają pasek aplikacji z naszego układu XML jako pasek działań dla tej aktywności. Wywołanie zwrotne onCreateOptionsMenu informuje aktywność, co ma być używane jako menu. W tym przypadku umieści on elementy menu z R.menu.shr_toolbar_menu na pasku aplikacji. Plik menu zawiera 2 elementy: „Szukaj” i „Filtruj”.

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>

Po wprowadzeniu tych zmian plik ProductGridFragment.kt powinien wyglądać tak:

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)
   }
}

Skompiluj i uruchom. Ekran główny powinien wyglądać tak:

Teraz pasek narzędzi zawiera ikonę nawigacji, tytuł i 2 ikony działań po prawej stronie. Pasek narzędzi wyświetla też wysokość za pomocą subtelnego cienia, który pokazuje, że znajduje się on na innej warstwie niż treść.

Aplikacja ma już pewną strukturę, więc uporządkujmy treści, umieszczając je na kartach.

Dodawanie karty

Zacznijmy od dodania jednej karty pod górnym paskiem aplikacji. Karta powinna zawierać obszar na obraz, tytuł i etykietę tekstu dodatkowego. Dodaj te informacje w sekcji shr_product_grid_fragment.xml pod sekcją 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>

Kompilowanie i uruchamianie:

W tym podglądzie widać, że karta jest odsunięta od lewej krawędzi, ma zaokrąglone rogi i cień (który wskazuje wysokość karty). Cały element nazywa się „kontenerem”. Oprócz kontenera wszystkie elementy w nim są opcjonalne.

Do kontenera możesz dodać te elementy: tekst nagłówka, miniaturę lub awatar, tekst podtytułu, separatory, a nawet przyciski i ikony. Na przykład utworzona przez nas karta zawiera 2 elementy TextView (jeden dla tytułu, a drugi dla tekstu dodatkowego) w elemencie LinearLayout, wyrównane do dołu karty.

Karty są zwykle wyświetlane w kolekcji z innymi kartami. W następnej sekcji tego laboratorium pokażemy, jak wyświetlić je w siatce.

Gdy na ekranie znajduje się kilka kart, są one zgrupowane w 1 lub więcej kolekcji. Karty w siatce są współpłaszczyznowe, co oznacza, że znajdują się na tej samej wysokości (chyba że zostaną podniesione lub przeciągnięte, ale nie będziemy tego omawiać w tym laboratorium).

Konfigurowanie siatki kart

Sprawdź shr_product_card.xml plik, który dla Ciebie przygotowaliśmy:

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>

Ten układ karty zawiera kartę z obrazem (w tym przypadku jest to NetworkImageView, który umożliwia wczytywanie i wyświetlanie obrazów z adresu URL) oraz 2 elementy TextViews.

Następnie przyjrzyj się ProductCardRecyclerViewAdapter, które dla Ciebie przygotowaliśmy. Jest w tym samym pakiecie co 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
   }
}

Klasa adaptera powyżej zarządza zawartością naszej siatki. Aby określić, co ma robić każdy widok z danymi treściami, wkrótce napiszemy kod dla onBindViewHolder().

W tym samym pakiecie możesz też sprawdzić ProductCardViewHolder. Ta klasa przechowuje widoki, które wpływają na układ karty, dzięki czemu możemy je później modyfikować.

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)

Aby skonfigurować siatkę, najpierw usuń symbol zastępczy MaterialCardViewshr_product_grid_fragment.xml. Następnie dodaj komponent reprezentujący siatkę kart. W tym przypadku użyjemy elementu RecyclerView. Dodaj komponent RecyclerView do elementu shr_product_grid_fragment.xml poniżej komponentu 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>

Plik shr_product_grid_fragment.xml powinien wyglądać tak:

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>

Na koniec w pliku onCreateView() dodaj kod inicjowania RecyclerView do pliku ProductGridFragment.kt po wywołaniu setUpToolbar(view) i przed instrukcją 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;
}

Powyższy fragment kodu zawiera niezbędne kroki inicjowania, które pozwalają skonfigurować RecyclerView. Obejmuje to ustawienie menedżera układu RecyclerView oraz zainicjowanie i ustawienie adaptera RecyclerView.

Plik ProductGridFragment.kt powinien teraz wyglądać tak:

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)
   }
}

Kompilowanie i uruchamianie:

Karty są już dostępne. Nie wyświetlają one jeszcze żadnych informacji, więc dodajmy dane o produktach.

Dodawanie obrazów i tekstu

Do każdej karty dodaj obraz, nazwę produktu i cenę. Nasza ViewHolder abstrakcja zawiera widoki poszczególnych kart. W naszym ViewHolder dodaj 3 widoki w ten sposób:

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)
}

Zaktualizuj metodę onBindViewHolder()ProductCardRecyclerViewAdapter, aby ustawić tytuł, cenę i zdjęcie produktu dla każdego widoku produktu, jak pokazano poniżej:

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)
   }
}

Powyższy kod informuje adapter RecyclerView o tym, co ma zrobić z każdą kartą, za pomocą ViewHolder.

W tym przypadku ustawia dane tekstowe w każdym z elementów ViewHolderTextView i wywołuje funkcję ImageRequester, aby pobrać obraz z adresu URL. ImageRequester to klasa, którą udostępniliśmy dla Twojej wygody. Korzysta ona z biblioteki Volley (to temat wykraczający poza zakres tych warsztatów, ale możesz samodzielnie zapoznać się z kodem).

Kompilowanie i uruchamianie:

Nasze produkty wyświetlają się teraz w aplikacji.

Nasza aplikacja ma podstawowy proces, który prowadzi użytkownika od ekranu logowania do ekranu głównego, na którym można wyświetlać produkty. W kilku wierszach kodu dodaliśmy górny pasek aplikacji z tytułem i 3 przyciskami oraz siatkę kart do prezentowania treści aplikacji. Ekran główny jest teraz prosty i funkcjonalny, ma podstawową strukturę i zawiera treści, które można wykorzystać.

Dalsze kroki

Użyliśmy już 4 podstawowych komponentów Material Design z biblioteki MDC-Android: górnego paska aplikacji, karty, pola tekstowego i przycisku. Więcej komponentów znajdziesz w katalogu MDC-Android.

Aplikacja jest w pełni funkcjonalna, ale nie ma jeszcze określonej marki ani stylu. W module MDC-103: Material Design Theming with Color, Shape, Elevation and Type dostosujemy styl tych komponentów, aby odzwierciedlały żywą, nowoczesną markę.

Udało mi się ukończyć to ćwiczenie w rozsądnym czasie i przy rozsądnym nakładzie pracy.

Zdecydowanie się zgadzam Zgadzam się Nie mam zdania Nie zgadzam się Zdecydowanie się nie zgadzam

Chcę nadal korzystać z komponentów Material w przyszłości

Zdecydowanie się zgadzam Zgadzam się Nie mam zdania Nie zgadzam się Zdecydowanie się nie zgadzam