RecyclerView и CardView. Новые виджеты в Android L

в 8:30, , рубрики: android, Разработка под android

Как известно, в июне проходила очередная конференция Google I/O, в ходе которой было вкратце рассказано о двух новых виджетах. И поскольку на хабре об этих виджетах пока ничего не написано, я решил написать эту статью с простенькой демонстрацией.

Демо приложение доступно на гитхабе по ссылке.

Собственно, под катом можно прочесть пару слов о RecyclerView, CardView и о подключении соответствующих библиотек в Gradle. Также, можно посмотреть коротенькое видео, демонстрирующее стандартную анимацию операций со списком в RecyclerView.

RecyclerView

RecyclerView, по сути, является эволюцией одного из самых необходимых в Android-разработке виджетов — ListView. Собственно, предназначение у него ровно то же самое — отображать список элементов, но есть нюансы:

1. Обязательное использование паттерна ViewHolder. Если при использовании ListView можно было из-за отсутствия опыта использовать адаптер, создающий с нуля отдельное view для каждого элемента списка, что при большом размере списка могло обернуться меньшей отзывчивостью UI и использованием лишней памяти, то при работе с RecyclerView разработчика насильно приводят к имплементации этого паттерна. Посмотрим, как это выглядит в коде адаптера для RecyclerView:

/**
 * Класс адаптера наследуется от RecyclerView.Adapter с указанием класса, который будет хранить ссылки на виджеты элемента списка, т.е. класса, имплементирующего ViewHolder. В нашем случае класс объявлен внутри класса адаптера.
 */
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder> {

    private List<Record> records;

    public RecyclerViewAdapter(List<Record> records) {
        this.records = records;
    }

    /**
     * Создание новых View и ViewHolder элемента списка, которые впоследствии могут переиспользоваться.
     */
    @Override
    public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
        View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.recyclerview_item, viewGroup, false);
        return new ViewHolder(v);
    }

    /**
     * Заполнение виджетов View данными из элемента списка с номером i
     */
    @Override
    public void onBindViewHolder(ViewHolder viewHolder, int i) {
        Record record = records.get(i);
        viewHolder.name.setText(record.getName());
    }

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

    /**
     * Реализация класса ViewHolder, хранящего ссылки на виджеты.
     */
    class ViewHolder extends RecyclerView.ViewHolder {
        private TextView name;
        private ImageView icon;

        public ViewHolder(View itemView) {
            super(itemView);
            name = (TextView) itemView.findViewById(R.id.recyclerViewItemName);
            icon = (ImageView) itemView.findViewById(R.id.recyclerViewItemIcon);
        }
    }
}

2. LayoutManager. Для использования RecyclerView кроме адаптера вам необходимо передать ему с помощью метода setLayoutManager() объект класса, реализующего LayoutManager. Этот класс отвечает за работу с адаптером, именно он решает, переиспользовать View или создать новый, и соответственно, именно он дёргает методы onCreateViewHolder(), onBindViewHolder() и getItemCount() адаптера. Пока доступна только одна реализация этого класса — LinearLayoutManager, для создания кастомного LayoutManager, необходимо унаследоваться от RecyclerView.LayoutManager.

3. Анимация операций со списком. Если вы смотрели презентацию дизайна Material, то могли заметить, что одной из основных его особенностей является плавность UI, которая достигается с помощью повсеместного использования анимации. Наверняка, при особом желании можно добавить анимацию и в ListView, мне пока не приходилось этим заниматься, но в RecyclerView это делается парой строчек кода:
— для объекта RecyclerView указывается класс, имплементирующий анимацию:

  RecyclerView.ItemAnimator itemAnimator = new DefaultItemAnimator();
        recyclerView.setItemAnimator(itemAnimator);

— при добавлении или удалении элемента списка вызывается метод адаптера notifyItemInserted(int position) или notifyItemRemoved(int position) соответственно.
При желании можно написать собственную реализацию анимации, унаследовавшись от RecyclerView.ItemAnimator.

Собственно и всё о RecyclerView, на гитхабе я выложил простенькое приложение, демонстрирующее, как можно использовать этот виджет. Запустив его, можно полюбоваться на анимацию добавления/удаления элемента (а можно посмотреть видео).

RecyclerView и CardView. Новые виджеты в Android L

CardView

CardView — это виджет, имплементирующий такой элемент дизайна Material, как карточка. По сути это контейнер, у которого можно задавать радиус скругленности углов, цвет карточки и высоту по оси z.
Например, вот такой код верстки:

 <android.support.v7.widget.CardView
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:id="@+id/cardView"
        card_view:cardCornerRadius="6dp"
        card_view:cardBackgroundColor="#84ffff">

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">


            <TextView
                android:id="@+id/info_text"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Test CardView"
                android:layout_centerInParent="true"
                android:textSize="18sp"
                android:textColor="#fff"/>
        </RelativeLayout>
</android.support.v7.widget.CardView>

Даст нам следующий результат (да, я не дизайнер):

RecyclerView и CardView. Новые виджеты в Android L

Сборка проекта, использующего новые виджеты

Для сборки с помощью Gradle нужно добавить в dependencies зависимости:

compile 'com.android.support:cardview-v7:+’
compile 'com.android.support:recyclerview-v7:+’

Но эти библиотеки автоматически меняют minSdk нашей сборки на версию L, поэтому для нормальной работы в AndroidManifest следует прописать параметр:

<uses-sdk tools:node="replace" />

Автор:

Источник

* - обязательные к заполнению поля