RecyclerView и CardView в Android

Добавлено: 25/02/2017 20:27 |  Обновлено: 18/06/2018 05:01 |  Добавил: nick |  Просмотры: 12702 Комментарии: 3
Вводная часть
В этом материале вы узнаете, как создать прокручиваемый список карточек или элементов списка, путем добавления виджета CardView в списковое представление RecyclerView. Данный функционал появился с приходом концепции материального оформления (Material Design), начиная с API версии 21.
Как это работает можно увидеть в моем приложении «Секретные карточки». Страница приложения в Google Play. ×
Готовый проект будет выглядеть следующим образом: Создадим новый проект в Android Studio. Код для материала был написан в этой IDE, но вы можете воспользоваться любой другой. Для этого примера я выбрал шаблон Scrolling Activity, который хорошо подходит для прокручиваемого содержимого и выполнен в соответствии концепции Material Design. После создания проекта приложение будет выглядеть следующим образом: Сразу скажу, что круглая кнопка в этом материале никак не задействована, но я ее оставил для будущего материала, посвященного работе с JSON, который будет основан на этом материале.

Для работы CardView и RecyclerView нужно добавить библиотеки recyclerview-v7 и cardview-v7 как зависимости. Это можно сделать через меню Android Studio (File – Project Structure – app – Dependencies) или вручную, добавив в файл app/build.gradle следующие строки (для API 26):
implementation 'com.android.support:cardview-v7:26.1.+'
implementation 'com.android.support:recyclerview-v7:26.1.+'
Еще раз о сути проекта. Мы создаем приложение, которое будет отображать прокручиваемый набор карточек. Для примера данные для карточек будут объектами класса Card с полями title и content. Поэтому создадим в папке с java-исходниками новый файл Card.java. Его содержимое будет следующим:
public class Card {
    String title;
    String content;

    Card(String title, String content) {
        this.title = title;
        this.content = content;
    }
}
Далее переходим к файлу ScrollingActivity.java, созданному автоматически, после выбора шаблона. Его содержимое (исключая методы: onCreateOptionsMenu() и onOptionsItemSelected()) будет следующим:
private List cards;
private RecyclerView rv;

@Override
protected void onCreate(Bundle savedInstanceState) {
    /* код по умолчанию */

    rv=(RecyclerView)findViewById(R.id.rv);

    LinearLayoutManager llm = new LinearLayoutManager(this);
    rv.setLayoutManager(llm);

    initializeData();
    initializeAdapter();
}

private void initializeData(){
    cards = new ArrayList<>();
    cards.add(new Card("Card 1", "Content 1"));
    cards.add(new Card("Card 2", "Content 2"));
    cards.add(new Card("Card 3", "Content 3"));
    cards.add(new Card("Card 4", "Content 4"));
    cards.add(new Card("Card 5", "Content 5"));
}

private void initializeAdapter(){
    RVAdapter adapter = new RVAdapter(cards);
    rv.setAdapter(adapter);
}
Переменной rv мы присваиваем ссылку на виджет RecyclerView, который нужно добавить в файл content_scrolling.xml, создаваемый автоматически после выбора шаблона. Разметка виджета следующая:
<android.support.v7.widget.RecyclerView
    android:layout_height="match_parent"
    android:layout_width="match_parent"
    android:id="@+id/rv"
    >

</android.support.v7.widget.RecyclerView> 
Далее в файле идут следующие строки:
LinearLayoutManager llm = new LinearLayoutManager(this);
rv.setLayoutManager(llm);
Они отвечают за способ размещения представлений в RecyclerView. Все представления будут отображаться в виде списка.

В методе initializeAdapter() создаем адаптер RVAdapter и передаем ему набор карточек. Адаптер заполняет данными компоненты TextView (title и content) для всех карточек. Адаптер будет размещен в одноименном файле RVAdapter.java.

Разметку для карточки разместим в файле cardview.xml (в папке layout). Содержимое файла будет следующим:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:id="@+id/cv"
    android:layout_margin="5dp"
    card_view:cardCornerRadius="4dp"
    >

        <LinearLayout
            android:orientation="vertical"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:padding="16dp">
            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:id="@+id/title"
                android:textSize="30sp"
                android:text=" " />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:id="@+id/content"
                android:text=" " />
        </LinearLayout>

</android.support.v7.widget.CardView> 
С разметкой закончили, теперь создадим файл RVAdapter.java. Его содержимое будет следующим:
public class RVAdapter extends RecyclerView.Adapter<RVAdapter.CardViewHolder> {

    List cards;

    public static class CardViewHolder extends RecyclerView.ViewHolder {

        CardView cardView;

        CardViewHolder(CardView cv) {
            super(cv);
            cardView = cv;
        }
    }

    RVAdapter(List cards){
        this.cards = cards;
    }

    @Override
    public CardViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        CardView cv = (CardView) LayoutInflater.from(parent.getContext())
                .inflate(R.layout.cardview, parent, false);
        return new CardViewHolder(cv);
    }

    @Override
    public void onBindViewHolder(CardViewHolder cardViewHolder, int position) {
        CardView cardView = cardViewHolder.cardView;
        TextView title = (TextView)cardView.findViewById(R.id.title);
        title.setText(cards.get(position).title);
        TextView content = (TextView)cardView.findViewById(R.id.content);
        content.setText(cards.get(position).content);

    }

    @Override
    public int getItemCount() {
        return cards.size();
    }
}
Несколько слов о коде. В методе onCreateViewHolder() создаем новое представление (карточку). В методе onBindViewHolder() заполняем представление данными.

Обработчик нажатий по карточкам
Допустим у вас в активности есть какой-то метод, который нужно запускать при нажатии по отдельной карточке. В этом разделе рассмотрим как это сделать.

Для примера добавим в активность метод, который показывает всплывающее сообщение в Snackbar. В сообщение будем передавать номер карточки по которой нажали.

Итак, добавим в активность новый метод showSnackbar() со следующим содержимым:
void showSnackbar(int position) {
    Snackbar.make(rv, "Карточка с номером "+position, Snackbar.LENGTH_LONG).show();
}
Далее нужно изменить код в файле RVAdapter.java. Откроем его.

В классе CardViewHolder после строчки CardView cardView; нужно добавить следующие строки:
int currentCardPosition;
Context mContext;
Конструктор CardViewHolder() нужно переписать следующим образом:
CardViewHolder(CardView cv, Context context) { //добавили Context context
    super(cv);
    cardView = cv;

    /* Показываем Snackbar */
    mContext=context;
    cardView.setOnClickListener(new View.OnClickListener() {
        @Override public void onClick(View v) {
            if(mContext instanceof ScrollingActivity){
                ((ScrollingActivity)mContext).showSnackbar(currentCardPosition);
            }
        }
    });
}
В методе onCreateViewHolder() нужно изменить строчку возвращаемого значения:
return new CardViewHolder(cv, cv.getContext());
Так как мы переписали конструктор CardViewHolder() в коде выше, здесь мы добавляем новый параметр cv.getContext().

В методе onBindViewHolder() нужно добавить новую строчку для передачи номера нажатой карточки в активность:
cardViewHolder.currentCardPosition = position;
На этом все. Теперь при нажатии по карточке, в окне приложения, вы будете видеть всплывающее сообщение Snackbar с номером нажатой карточки.

Оставьте свой комментарий

Комментарии