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

1. Wprowadzenie

logo_components_color_2x_web_96dp.png

Komponenty Material Design (MDC) pomagają deweloperom wdrażać Material Design. MDC to biblioteka stworzona przez zespół inżynierów i projektantów UX w Google. Zawiera dziesiątki pięknych i funkcjonalnych komponentów UI. Jest dostępna na Androida, iOS, web i Flutter.material.io/develop

W tym kursie kodowania (MDC-101) do utworzenia strony logowania użyliśmy 2 komponentów Material Design: pól tekstowych i przycisków z efektem falowania. Rozwińmy te podstawy, dodając nawigację, strukturę i dane.

Co utworzysz

W tym Codelab utworzysz ekran główny dla aplikacji Shrine, która jest aplikacją e-commerce sprzedającą odzież i wyposażenie domowe. Będą one zawierać:

  • Pasek aplikacji u góry
  • Lista siatki pełna produktów

249db074eff043f4.png

Komponenty MDC-Android w tym ćwiczeniu z programowania

  • AppBarLayout
  • MaterialCardView

Czego potrzebujesz

  • podstawowa wiedza o programowaniu aplikacji na Androida;
  • Android Studio (pobierz tę aplikację stąd, jeśli jeszcze jej nie masz)
  • emulator lub urządzenie z Androidem (dostępne w Android Studio).
  • Przykładowy kod (patrz następny krok)

Jak oceniasz swój poziom doświadczenia w tworzeniu aplikacji na Androida?

Początkujący Średnio zaawansowany Zaawansowany

2. Konfigurowanie środowiska programistycznego

Czy kontynuujesz na podstawie szkolenia MDC-101?

Jeśli masz ukończone MDC-101, Twój kod powinien być gotowy do wykonania tego ćwiczenia z programowania. Przejdź do kroku 3. Dodaj górny pasek aplikacji.

Zaczynasz od zera?

Pobierz startową aplikację Codelabs

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

...lub skopiuj je z GitHuba

Aby skopiować to laboratorium programistyczne 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

Wczytywanie kodu startowego w Android Studio

  1. Gdy kreator konfiguracji zakończy działanie i pojawi się okno Witamy w Android Studio, kliknij Otwórz istniejący projekt Android Studio. Przejdź do katalogu, w którym zainstalowano przykładowy kod, i wybierz kotlin -> shrine (lub wyszukaj na komputerze shrine), aby otworzyć projekt Shipping.
  2. Poczekaj, aż Android Studio skompiluje i zsynchronizuje projekt, zgodnie ze wskaźnikami aktywności u dołu okna Android Studio.
  3. W tym momencie Android Studio może wyświetlić błędy kompilacji, ponieważ brakuje pakietu Android SDK lub narzędzi do kompilacji, takich jak pokazane poniżej. Postępuj zgodnie z instrukcjami w Android Studio, aby zainstalować lub zaktualizować te aplikacje i zsynchronizować projekt.

KzoYWC1S7Se7yL8igi1vXF_mbVxAdl2lg5kb7RODrsVpEng0G6U3NK1Qnn0faBBZd2u71yMXioy9tD-7fv3NXvVO4N3EtMMeWDTmqBMMl6egd9R5uXX0T_SKmahbmRor3wZZHX0ByA

Dodawanie zależności projektu

Projekt musi być zależny od biblioteki obsługi MDC na Androida. Ta zależność powinna już być widoczna w pobranym przykładowym kodzie, ale warto wykonać te czynności, aby mieć pewność.

  1. Przejdź do pliku build.gradle modułu app i upewnij się, że blok dependencies zawiera zależność od MDC na Androidzie:
api 'com.google.android.material:material:1.1.0-alpha06'
  1. (Opcjonalnie) W razie potrzeby zmodyfikuj plik build.gradle, aby dodać te zależności i zsynchronizować 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'
}

Uruchamianie aplikacji startowej

  1. Upewnij się, że konfiguracja kompilacji po lewej stronie przycisku Uruchom / Odtwórz to app.
  2. Aby skompilować i uruchomić aplikację, naciśnij zielony przycisk Uruchom / Graj.
  3. Jeśli masz już urządzenie z Androidem na liście dostępnych urządzeń, w oknie Wybierz cel wdrożenia przejdź do kroku 8. W przeciwnym razie kliknij Utwórz nowe urządzenie wirtualne.
  4. Na ekranie Wybierz sprzęt wybierz telefon, na przykład Pixel 2, i kliknij Dalej.
  5. Na ekranie Obraz systemu wybierz najnowszą wersję Androida, najlepiej z najwyższym poziomem interfejsu API. Jeśli aplikacja nie jest zainstalowana, kliknij widoczny link Pobierz i dokończ pobieranie.
  6. Kliknij Dalej.
  7. Na ekranie Urządzenie wirtualne z Androidem (AVD) pozostaw ustawienia bez zmian i kliknij 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 ją na urządzeniu docelowym.

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

4cb0c218948144b4.png

Teraz gdy ekran logowania wygląda dobrze, dodajmy do aplikacji kilka produktów.

3. Dodawanie paska aplikacji u góry

Po zamknięciu strony logowania wyświetla się ekran główny z komunikatem „Gotowe!”. Wspaniale. Jednak teraz użytkownik nie może nic zrobić ani nie ma żadnego wglądu w to, gdzie się znajduje w aplikacji. Aby ułatwić sobie zadanie, dodaj nawigację.

Material Design zapewnia dużą wygodę korzystania z nawigacji. Jednym z najbardziej widocznych komponentów jest pasek aplikacji u góry.

Aby zapewnić nawigację i szybki dostęp do innych działań, dodajmy pasek aplikacji u góry.

Dodawanie widżetu paska aplikacji

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

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>

Twoje shr_product_grid_fragment.xml powinno 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 ikonę menu.

Dodawanie ikony nawigacji

Nie wychodząc z interfejsu shr_product_grid_fragment.xml, do komponentu XML Toolbar dodanego właśnie do układu dodaj ten kod:

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 stylizacja górnego paska aplikacji

Możesz też dodać przyciski po prawej stronie paska aplikacji. Na Androidzie są one nazywane przyciskami polecenia. Spersonalizujemy górny pasek aplikacji i dodamy do jego menu przyciski poleceń za pomocą programowania.

W funkcji onCreateView obiektu ProductGridFragment.kt ustaw parametr Toolbar obiektu activity jako parametr ActionBar za pomocą funkcji setSupportActionBar. Możesz to zrobić po utworzeniu widoku za pomocą 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ąpimy onCreateOptionsMenu, aby wczytać 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ąpij onCreate()ProductGridFragment.kt, a po wywołaniu super() wywołaj setHasOptionMenu z wartością true:

ProductGridFragment.kt

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

Powyższe fragmenty kodu ustawiają pasek aplikacji z układu XML jako pasek czynności dla tej aktywności. Funkcja wywołania zwrotnego onCreateOptionsMenu informuje aktywność, co użyć jako menu. W tym przypadku elementy menu z R.menu.shr_toolbar_menu zostaną umieszczone 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)
   }
}

Twórz i uruchamiaj. Ekran główny powinien wyglądać tak:

d04e8aa3b27f4754.png

Teraz na pasku narzędzi są ikona nawigacji, tytuł i dwie ikony działań po prawej stronie. Pasek narzędzi wyświetla też wzniesienie za pomocą subtelnego cienia, który pokazuje, że znajduje się ono na innej warstwie niż zawartość.

4. Dodaj kartę

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

Dodaj kartę

Zacznijmy od dodania karty pod górnym paskiem aplikacji. Karta powinna zawierać obszar na obraz, tytuł i etykietę dodatkowego tekstu. Dodaj ten kod w polu shr_product_grid_fragment.xml poniżej 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>

Utwórz i uruchom:

f6184a55ccb5f920.png

Na tym podglądzie widać, że karta jest wstawiona od lewej krawędzi, ma zaokrąglone rogi i cień (odzwierciedlający wysokość karty). Cały element nazywa się „kontenerem”. Poza kontenerem wszystkie elementy w nim są opcjonalne.

Do kontenera możesz dodać te elementy: tekst nagłówka, miniaturę lub awatar, tekst nagłówka, podziały, a nawet przyciski i ikony. Na przykład karta, którą właśnie utworzyliśmy, zawiera 2 elementy TextView (jeden dla tytułu, a drugi dla tekstu dodatkowego) w elementach LinearLayout wyrównanych do dołu karty.

Karty są zwykle wyświetlane w kolekcji z innymi kartami. W następnej sekcji tego Codelab umieścimy je w ramach kolekcji w siatce.

5. Tworzenie siatki kart

Jeśli na ekranie jest kilka kart, są one zgrupowane w jedną lub więcej kolekcji. Karty w siatce są współpłaskie, co oznacza, że mają ten sam poziom odpoczynku (chyba że zostaną podniesione lub przeciągnięte, ale nie będziemy tego omawiać w tym CodeLab).

Konfigurowanie siatki kart

Zapoznaj się z plikiem shr_product_card.xml, który Ci udostępniliś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 NetworkImageView, która umożliwia wczytywanie i wyświetlanie obrazów z adresu URL) oraz 2 elementy TextViews.

Następnie zapoznaj się z przygotowanymi przez nas ProductCardRecyclerViewAdapter. 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 zarządza zawartością siatki. Aby określić, co każdy widok powinien robić z daną treścią, wkrótce napiszemy kod dla onBindViewHolder().

W tym samym pakiecie możesz też przyjrzeć się 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ń element zastępczy MaterialCardView z elementu shr_product_grid_fragment.xml. Następnie dodaj komponent reprezentujący siatkę kart. W tym przypadku użyjemy RecyclerView. Dodaj komponent shr_product_grid_fragment.xml do elementu XML AppBarLayout poniżej elementu 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 funkcji ProductGridFragment.kt po wywołaniu funkcji 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 kroki inicjowania niezbędne do skonfigurowania RecyclerView. Obejmuje to wybór menedżera układu RecyclerView oraz zainicjowanie i ustawienie adaptera RecyclerView.

Twój 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)
   }
}

Utwórz i uruchom:

f9aeab846fc3bb4c.png

Karty są już dostępne. Nic jeszcze nie wyświetla, więc dodajmy dane o produktach.

Dodawanie obrazów i tekstu

Do każdej karty dodaj zdjęcie, nazwę produktu i cenę. Abstrakcyjna klasa ViewHolder przechowuje widoki każdej karty. W naszym ViewHolder dodaj te 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() w 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, co ma zrobić z każdą kartą, za pomocą ViewHolder.

Ustawia tutaj dane tekstowe w TextViewViewHolder i wywołuje funkcję ImageRequester, by pobrać obraz z adresu URL. Klasa ImageRequester została udostępniona dla ułatwienia i korzysta z biblioteki Volley (jest to temat wykraczający poza zakres tego Codelab, ale możesz zapoznać się z tym kodem samodzielnie).

Kompilacja i uruchamianie:

249db074eff043f4.png

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

6. Podsumowanie

Nasza aplikacja ma podstawowy proces, który prowadzi użytkownika od ekranu logowania do ekranu głównego, na którym można przeglądać produkty. W zaledwie kilku linijkach kodu dodaliśmy górny pasek aplikacji z tytułem i 3 przyciskami oraz siatkę kart prezentujących zawartość aplikacji. Ekran główny jest teraz prosty i funkcjonalny, a jego podstawowa struktura zawiera treści, które można wykorzystać.

Dalsze kroki

Użyliśmy 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 na Androida.

Aplikacja jest w pełni funkcjonalna, ale nie podkreśla jeszcze żadnej marki ani stylu. W poradniku MDC-103: Material Design Theming with Color, shape, Elevation and Type, dostosujemy styl tych komponentów, aby podkreślić żywą, nowoczesną markę.

Udało mi się ukończyć to ćwiczenia z programowania w rozsądny sposób i w rozsądny sposób

Całkowicie się zgadzam Zgadzam się Nie mam zdania Nie zgadzam się Całkowicie się nie zgadzam

Chcę nadal używać komponentów Material Components

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