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

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 samouczku MDC-101 do utworzenia strony logowania użyto 2 komponentów Material Design (MDC): pól tekstowych i przycisków. 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 udało Ci się ukończyć MDC-101, Twój kod powinien być gotowy do tego ćwiczenia. Możesz przejść 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/java. 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 java –> shrine(lub wyszukaj na komputerze shrine), aby otworzyć projekt Shrine.
  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 najważniejszych elementów nawigacji 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

shr_product_grid_fragment.xml usuń tag <LinearLayout> zawierający tekst „Udało 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 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

W aplikacji shr_product_grid_fragment.xml dodaj do komponentu XML Toolbar (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 poleceń.

Najpierw utwórzmy metodę konfigurowania paska narzędzi. Metoda powinna pobrać odwołanie do paska narzędzi za pomocą id, a także odwołanie do aktywności za pomocą getActivity(). Jeśli aktywność nie jest wartością null, ustaw Toolbar, aby używać go jako ActionBar za pomocą setSupportActionBar:

ProductGridFragment.java

private void setUpToolbar(View view) {
   Toolbar toolbar = view.findViewById(R.id.app_bar);
   AppCompatActivity activity = (AppCompatActivity) getActivity();
   if (activity != null) {
       activity.setSupportActionBar(toolbar);
   }
}

Następnie bezpośrednio pod dodaną metodą setUpToolbar zastąpmy metodę onCreateOptionsMenu, aby umieścić zawartość shr_toolbar_menu.xml na pasku narzędzi:

ProductGridFragment.java

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater menuInflater) {
   menuInflater.inflate(R.menu.shr_toolbar_menu, menu);
   super.onCreateOptionsMenu(menu, menuInflater);
}

Teraz dodaj wywołanie metody setUpToolbar, którą dodaliśmy do treści metody onCreateView(), w ten sposób:

ProductGridFragment.java

@Override
public View onCreateView(
       @NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
   // Inflate the layout for this fragment with the ProductGrid theme
   View view = inflater.inflate(R.layout.shr_product_grid_fragment, container, false);

   // Set up the toolbar
   setUpToolbar(view);

   return view;
}

Na koniec dodaj onCreate() do ProductGridFragment.java. W treści metody ustaw parametr setHasOptionMenu jako true.

Metoda powinna wyglądać tak:

ProductGridFragment.java

@Override
public void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   setHasOptionsMenu(true);
}

Powyższy kod ustawia 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.java powinien wyglądać tak:

ProductGridFragment.java

package com.google.codelabs.mdc.java.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 android.widget.Toolbar;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;


public class ProductGridFragment extends Fragment {

   @Override
   public void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setHasOptionsMenu(true);
   }
  
   @Override
   public View onCreateView(
           @NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
       // Inflate the layout for this fragment with the ProductGrid theme
       View view = inflater.inflate(R.layout.shr_product_grid_fragment, container, false);

       // Set up the toolbar
       setUpToolbar(view);

       return view;
   }
  
   private void setUpToolbar(View view) {
       Toolbar toolbar = view.findViewById(R.id.app_bar);
       AppCompatActivity activity = (AppCompatActivity) getActivity();
       if (activity != null) {
           activity.setSupportActionBar(toolbar);
       }
   }

   @Override
   public void 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 jest też wyświetlany z niewielkim cieniem, który wskazuje, ż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.

W pliku shr_product_grid_fragment.xml dodaj pod elementem AppBarLayout ten kod:

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 ekranu, ma zaokrąglone rogi i cień (który wskazuje wysokość karty). Cały obszar nazywa się „kontenerem”. Oprócz samego 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 NetworkImageView, co pozwala nam umieszczać obrazy z adresu URL) i 2 elementy TextViews.

Następnie przyjrzyj się ProductCardRecyclerViewAdapter, które dla Ciebie przygotowaliśmy. Jest w tym samym pakiecie co ProductGridFragment.

ProductCardRecyclerViewAdapter.java

package com.google.codelabs.mdc.java.shrine;

import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

import com.google.codelabs.mdc.java.shrine.network.ImageRequester;
import com.google.codelabs.mdc.java.shrine.network.ProductEntry;

import java.util.List;

/**
* Adapter used to show a simple grid of products.
*/
public class ProductCardRecyclerViewAdapter extends RecyclerView.Adapter<ProductCardViewHolder> {

   private List<ProductEntry> productList;
   private ImageRequester imageRequester;

   ProductCardRecyclerViewAdapter(List<ProductEntry> productList) {
       this.productList = productList;
       imageRequester = ImageRequester.getInstance();
   }

   @NonNull
   @Override
   public ProductCardViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
       View layoutView = LayoutInflater.from(parent.getContext()).inflate(R.layout.shr_product_card, parent, false);
       return new ProductCardViewHolder(layoutView);
   }

   @Override
   public void onBindViewHolder(@NonNull ProductCardViewHolder holder, int position) {
       // TODO: Put ViewHolder binding code here in MDC-102
   }

   @Override
   public int getItemCount() {
       return productList.size();
   }
}

Klasa adaptera powyżej zarządza zawartością naszej siatki. Aby określić, co ma robić każdy widok z daną treścią, 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.java

package com.google.codelabs.mdc.java.shrine;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import android.view.View;

public class ProductCardViewHolder extends RecyclerView.ViewHolder {

   public ProductCardViewHolder(@NonNull View itemView) {
       super(itemView);
       // TODO: Find and store views from 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 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.java po wywołaniu setUpToolbar(view) i przed instrukcją return:

ProductGridFragment.java

@Override
public View onCreateView(
       @NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
   ...
   setUpToolbar(view);

   // Set up the RecyclerView
   RecyclerView recyclerView = view.findViewById(R.id.recycler_view);
   recyclerView.setHasFixedSize(true);
   recyclerView.setLayoutManager(new GridLayoutManager(getContext(), 2, GridLayoutManager.VERTICAL, false));
   ProductCardRecyclerViewAdapter adapter = new ProductCardRecyclerViewAdapter(
           ProductEntry.initProductEntryList(getResources()));
   recyclerView.setAdapter(adapter);
   int largePadding = getResources().getDimensionPixelSize(R.dimen.shr_product_grid_spacing);
   int smallPadding = getResources().getDimensionPixelSize(R.dimen.shr_product_grid_spacing_small);
   recyclerView.addItemDecoration(new 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.java powinien teraz wyglądać tak:

ProductGridFragment.java

package com.google.codelabs.mdc.java.shrine;

import android.os.Bundle;
import androidx.recyclerview.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toolbar;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.GridLayoutManager;


import com.google.codelabs.mdc.java.shrine.network.ProductEntry;

public class ProductGridFragment extends Fragment {

   @Override
   public void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setHasOptionsMenu(true);
   }

   @Override
   public View onCreateView(
           @NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
       // Inflate the layout for this fragment with the ProductGrid theme
       View view = inflater.inflate(R.layout.shr_product_grid_fragment, container, false);

       // Set up the toolbar
       setUpToolbar(view);

       // Set up the RecyclerView
       RecyclerView recyclerView = view.findViewById(R.id.recycler_view);
       recyclerView.setHasFixedSize(true);
       recyclerView.setLayoutManager(new GridLayoutManager(getContext(), 2, GridLayoutManager.VERTICAL, false));
       ProductCardRecyclerViewAdapter adapter = new ProductCardRecyclerViewAdapter(
               ProductEntry.initProductEntryList(getResources()));
       recyclerView.setAdapter(adapter);
       int largePadding = getResources().getDimensionPixelSize(R.dimen.shr_product_grid_spacing);
       int smallPadding = getResources().getDimensionPixelSize(R.dimen.shr_product_grid_spacing_small);
       recyclerView.addItemDecoration(new ProductGridItemDecoration(largePadding, smallPadding));

       return view;
   }

   private void setUpToolbar(View view) {
       Toolbar toolbar = view.findViewById(R.id.app_bar);
       AppCompatActivity activity = (AppCompatActivity) getActivity();
       if (activity != null) {
           activity.setSupportActionBar(toolbar);
       }
   }

   @Override
   public void onCreateOptionsMenu(Menu menu, MenuInflater menuInflater) {
       menuInflater.inflate(R.menu.shr_toolbar_menu, menu);
       super.onCreateOptionsMenu(menu, menuInflater);
   }

}

Skompiluj i uruchom.

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.java

package com.google.codelabs.mdc.java.shrine;

import androidx.recyclerview.widget.RecyclerView;
import android.view.View;
import android.widget.TextView;
import androidx.annotation.NonNull;

import com.android.volley.toolbox.NetworkImageView;

public class ProductCardViewHolder extends RecyclerView.ViewHolder {

   public NetworkImageView productImage;
   public TextView productTitle;
   public TextView productPrice;

   public ProductCardViewHolder(@NonNull View itemView) {
       super(itemView);
       productImage = itemView.findViewById(R.id.product_image);
       productTitle = itemView.findViewById(R.id.product_title);
       productPrice = itemView.findViewById(R.id.product_price);
   }
}

W adapterze RecyclerView w funkcji ViewHolder, zaktualizuj metodę onBindViewHolder(), aby ustawić informacje w każdym widoku:

ProductCardRecyclerViewAdapter.java

@Override
public void onBindViewHolder(@NonNull ProductCardViewHolder holder, int position) {
   if (productList != null && position < productList.size()) {
       ProductEntry product = productList.get(position);
       holder.productTitle.setText(product.title);
       holder.productPrice.setText(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 komponentów w MDC Android.

Aplikacja jest w pełni funkcjonalna, ale nie promuje jeszcze żadnej konkretnej marki. 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