Mamy zdefiniowane rodzaje elementów, obiekty typu view holder dla nich, abstrakcyjny adapter oparty o typy generyczne, oraz renderujący listę RecyclerView
. Pozostało nam już tylko podłączyć do elementów listy metody obsługujące kliknięcia. W głównej aktywności dodamy też metody pozwalające na zareagowanie w różny sposób dla każdego typu elementu.
9. Listenery kliknięc w elementy listy
Najpierw zdefiniujmy interfejs listenera:
ItemClickListener.java
public interface ItemClickListener { void onItemClick(View view, int position); }
Metoda onItemClick będzie przyjmowała widok z którego przyszło kliknięcie oraz pozycję na liście klikniętego elementu.
Poprawmy definicję adaptera abstrakcyjnego tak, aby implementował ten interfejs:
AbstractAdapter.java
public abstract class AbstractAdapter<I, VH extends AbstractRecyclerViewHolder> extends RecyclerView.Adapter<VH> implements ItemClickListener { // ... }
10. Implementacja metody onClick w AbstractRecyclerViewHolder
Aby nasze elementy obsługiwały kliknięcia musimy w holderze abstrakcyjnym zaimplementować OnClickListener. Dzięki temu będziemy mogli nadpisać metodę onClick. Będzie ona pobierać pozycję elementu z adeptera i wywoływać metodę przekazanego listenera onItemClick. Potrzebny jest jeszcze tylko setter dla listenera i pole typu ItemClickListener. Całość powinna wyglądać następująco:
AbstractRecyclerViewHolder.java
public abstract class AbstractRecyclerViewHolder<T> extends RecyclerView.ViewHolder implements View.OnClickListener { protected ItemClickListener mItemClickListener; public AbstractRecyclerViewHolder(View itemView) { super(itemView); super.itemView.setOnClickListener(this); } public void setItemClickListener(ItemClickListener itemClickListener) { mItemClickListener = itemClickListener; } @Override public void onClick(View view) { if (mItemClickListener != null) { int adapterPosition = getAdapterPosition(); if (adapterPosition != RecyclerView.NO_POSITION) { mItemClickListener.onItemClick(view, adapterPosition); } } } // ... }
11. Implementacja metody onItemClick w adapterze
Teraz wszystkie konkretne adaptery dziedziczące po klasie AbstractAdapter
będą musiały zaimplementować metodę onItemClick
. Dodajmy więc ją do RecycledListAdapter
’a, wypełnieniem jej zajmiemy się później:
RecycledListAdapter.java
@Override public void onItemClick(View view, int position) { // TODO: do something on item click }
Pozostało podłączyć listener z view holderem. W tym celu w metodzie onCreateViewHolder
adapterów konkretnych dodajemy na końcu linijkę kodu:
RecycledListAdapter.java
@Override public AbstractRecyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { // ... viewHolder.setItemClickListener(this); return viewHolder; }
Kliknięcie w dowolny element recyclera spowoduje wywołanie metody onItemClick
w naszej klasie RecycledListAdapter
. Należy mieć na uwadze, że obsługujemy również kliknięcie w nagłówek sekcji, tak więc w naszym przypadku, kiedy pierwszym elementem recyclera jest nagłówek, otrzymamy dla niego wartość argumentu position = 0. Możemy zróżnicować obsługę kliknięcia w zależności od typu elementu, np. ignorować kliknięcia w nagłówek a dla pozostałych typów wywołać odpowiednią metodę (callback) w głównej aktywności. Użyjemy do tego metody getItemViewType()
:
RecycledListAdapter.java
@Override public void onItemClick(View view, int position) { Log.d(TAG, "onItemClick: " + Integer.toString(position)); int itemViewType = getItemViewType(position); switch (RecycledListItem.ItemType.values()[itemViewType]) { case BOOK: listener.onBookItemClickListener((Book) items.get(position).getValue()); break; case DVD: listener.onDVDItemClickListener((Dvd) items.get(position).getValue()); break; case HEADER: default: break; }
No dobrze, ale przecież nie mamy takich metod w MainActivit
y, jak również nie ma też obiektu listener w klasie RecycledListAdapter
.
12. Metody w MainActivity
reagujące na kliknięcie w element listy
Najpierw zdefiniujmy interfejs:
RecycledListItemClickListener.java
public interface RecycledListItemClickListener { void onBookItemClickListener(Book model); void onDVDItemClickListener(Dvd model); }
Będziemy mieć dwie metody które w wyniku kliknięcia w element listy otrzymają model odpowiadający temu elementowi.
Zaimplementujmy je w głównej aktywności, oraz przekażmy do adaptera listener, którym od teraz jest nasza aktywność.
MainActivity.java
public class MainActivity extends AppCompatActivity implements RecycledListItemClickListener { // ... protected void initViews() { listRecyclerView = (RecyclerView) findViewById(R.id.list_recycler); adapter = new RecycledListAdapter(); listRecyclerView.setLayoutManager(new LinearLayoutManager(this)); listRecyclerView.setAdapter(adapter); items = MockAPI.retrieveData(); adapter.setItems(items); adapter.setItemClickListener(this) } @Override public void onBookItemClickListener(Book book) { Log.d(TAG, "Book clicked: " + book.toString()); } @Override public void onDVDItemClickListener(Dvd dvd) { Log.d(TAG, "DVD clicked: " + dvd.toString()); } }
Brakuje jeszcze tylko metody ustawiające w adapterze listener:
RecycledListAdapter.java
public class RecycledListAdapter extends AbstractAdapter<RecycledListItem, AbstractRecyclerViewHolder> { private static final String TAG = RecycledListAdapter.class.getSimpleName(); private RecycledListItemClickListener listener; // ... public void setItemClickListener(RecycledListItemClickListener listener) { this.listener = listener; } }
W ten sposób możemy sobie obsłużyć w różny sposób kliknięcia w różne elementy listy. Z głównej aktywności możemy sobie otwierać np. nową aktywność z widokami szczegółów np. książki czy płyty DVD – mającymi przecież różne layouty, logikę i funkcjonalności.
To wszystko jeśli chodzi o tworzenie recyclera z różnymi typami elementów. Teraz w prosty sposób można rozszerzać listę o kolejne typy i ich zróżnicowaną obsługę. Cały layout ekranu funkcjonalnego w naszej aplikacji można zbudować w oparciu o przewijalny recycler i poszczególne klocki interfejsu użytkownika będącymi jego elementami. Oczywiście pozostało jeszcze zasilić naszą listę konkretnymi danymi pochodzącymi z realnego API lub bazy danych, ale to już temat na osobny tutorial.
Cały kod dostępny jest na GitHubie.