Android. Jak zrobić wydajną listę zawierającą elementy różnego typu przy pomocy RecyclerView. Cz.3

android-128Mamy 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 MainActivity, 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&lt;RecycledListItem, AbstractRecyclerViewHolder&gt; {

    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.

Podziel się:
Facebooktwittergoogle_plusredditpinterestlinkedintumblrmail

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *