Пример урока по использованию Android RecyclerView и Android CardView

Android RecyclerView и Android CardView были представлены в Android Lollipop с Material Design. Для тех, кто не знаком с Material Design, это обширное руководство по виджетам пользовательского интерфейса, введенное с Android 5.0, которое улучшает визуальное привлекательность приложений.

Android RecyclerView

Android RecyclerView – это более продвинутая, мощная и гибкая версия ListView. Android RecyclerView похож на ListView, за исключением того, что он заставляет нас использовать класс RecyclerView.ViewHolder для хранения элементов, что не является обязательным для ListView. Как следует из названия, Android RecyclerView используется для повторного использования ячеек при прокрутке вверх и вниз путем переработки элементов в списке. Еще одним улучшением в RecyclerView является то, что он позволяет нам динамически устанавливать LayoutManagers во время выполнения, в отличие от ListView, который был доступен только в вертикальном списке прокрутки. RecyclerView позволяет устанавливать следующие типы макетов во время выполнения.

  • LinearLayoutManager: поддерживает как вертикальные, так и горизонтальные списки.
  • StaggeredLayoutManager: он поддерживает перемещенные списки
  • GridLayoutManager: он поддерживает отображение сеток, как это было раньше в GalleryView

Классы Android RecyclerView

  • Класс RecyclerView.ItemAnimator обеспечивает лучшую поддержку анимации видов, в отличие от ListView
  • Класс RecyclerView.ItemDecorator обеспечивает лучшую поддержку при добавлении границ и разделителей, тем самым предоставляя нам огромный контроль

Таким образом, RecyclerView более настраиваемый по сравнению с ListView и предоставляет больший контроль пользователям. RecyclerView доступен в библиотеке поддержки. Поэтому нам нужно изменить наш скрипт gradle, чтобы добавить следующую зависимость.

dependencies {
       compile 'com.android.support:recyclerview-v7:21.0.0-rc1'
 }

Карточное представление Android

Компонент пользовательского интерфейса Android CardView отображает информацию внутри карточек. Этот компонент обычно используется для отображения контактной информации. Этот компонент доступен в другой библиотеке поддержки, поэтому нам также нужно добавить его зависимость.

dependencies {
        compile 'com.android.support:cardview-v7:21.0.0-rc1'
        compile 'com.android.support:recyclerview-v7:21.0.0-rc1'
 }

Виджет Android CardView позволяет нам контролировать цвет фона, тень, радиус углов, высоту и т. д. Для использования пользовательских атрибутов в XML необходимо добавить следующее объявление пространства имен к родительскому макету. Ниже приведено объявление пространства имен с некоторыми атрибутами из нашего проекта.

<android.support.v7.widget.CardView
        android:id="@+id/card_view"
        xmlns:card_view="https://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        card_view:cardBackgroundColor="@color/grey_300"
        card_view:cardCornerRadius="10dp"
        card_view:cardElevation="5dp"
        card_view:cardUseCompatPadding="true">

Важные использованные выше атрибуты:

  • card_view:cardCornerRadius: Используется для задания радиуса углов в наших макетах
  • card_view:cardBackgroundColor: Используется для задания цвета фона представления

В нашем примере проекта мы добавим RecyclerView для отображения списка CardViews, содержащих названия и номера версий Android, а также образец логотипа. Обработчик события onclick для CardView настроен на удаление этой карточки из списка. Мы добавили опцию меню в ActionBar для добавления обратно удаленных карточек в определенном порядке. Примечание: изображения логотипов выбираются случайным образом из Google. Поэтому их размеры могут отличаться.

Пример использования Android RecyclerView и CardView

Проект состоит из MainActivity, который отображает RecyclerView. CardView добавляется в RecyclerView из класса CustomAdapter. DataModel используется для извлечения данных для каждого CardView через методы доступа. Класс MyData содержит массивы текстовых представлений и рисунков вместе с их идентификаторами.

Пример кода для Android RecyclerView и CardView

Файл activity_main.xml содержит RecyclerView внутри RelativeLayout, как показано ниже. Код activity_main.xml:

<RelativeLayout xmlns:android="https://schemas.android.com/apk/res/android"
    xmlns:tools="https://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity"
    android:background="@color/grey_300"
    >

    <android.support.v7.widget.RecyclerView
        android:id="@+id/my_recycler_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scrollbars="vertical"
        />

</RelativeLayout>

Макет CardView для Android определен ниже: Код cards_layout.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:tag="cards main container">

    <android.support.v7.widget.CardView
        android:id="@+id/card_view"
        xmlns:card_view="https://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        card_view:cardBackgroundColor="@color/color_white"
        card_view:cardCornerRadius="10dp"
        card_view:cardElevation="5dp"
        card_view:cardUseCompatPadding="true">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            >

            <ImageView
                android:id="@+id/imageView"
                android:tag="image_tag"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_margin="5dp"
                android:layout_weight="1"
                android:src="@drawable/ic_launcher"/>

            <LinearLayout
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_marginTop="12dp"
                android:layout_weight="2"
                android:orientation="vertical"
                >

                <TextView
                    android:id="@+id/textViewName"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_gravity="center_horizontal"
                    android:layout_marginTop="10dp"
                    android:text="Android Name"
                    android:textAppearance="?android:attr/textAppearanceLarge"/>

                <TextView
                    android:id="@+id/textViewVersion"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_gravity="center_horizontal"
                    android:layout_marginTop="10dp"

                    android:text="Android Version"
                    android:textAppearance="?android:attr/textAppearanceMedium"/>

            </LinearLayout>
        </LinearLayout>

    </android.support.v7.widget.CardView>

</LinearLayout>

CardView для Android содержит ImageView вместе с двумя TextView во вложенном линейном макете. Файл menu_main.xml содержит один элемент для возврата удаленных карт. Код menu_main.xml:

<menu xmlns:android="https://schemas.android.com/apk/res/android"
    xmlns:app="https://schemas.android.com/apk/res-auto"
    xmlns:tools="https://schemas.android.com/tools"
    tools:context=".MainActivity">
    <item android:id="@+id/add_item"
        android:title="Add"
        android:orderInCategory="100"
        app:showAsAction="always"/>
</menu>

Класс MainActivity.java определен ниже:

package com.journaldev.recyclerviewcardview;

import android.content.Context;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;

import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {

    private static RecyclerView.Adapter adapter;
    private RecyclerView.LayoutManager layoutManager;
    private static RecyclerView recyclerView;
    private static ArrayList data;
    static View.OnClickListener myOnClickListener;
    private static ArrayList removedItems;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        myOnClickListener = new MyOnClickListener(this);

        recyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);
        recyclerView.setHasFixedSize(true);

        layoutManager = new LinearLayoutManager(this);
        recyclerView.setLayoutManager(layoutManager);
        recyclerView.setItemAnimator(new DefaultItemAnimator());

        data = new ArrayList();
        for (int i = 0; i < MyData.nameArray.length; i++) {
            data.add(new DataModel(
                    MyData.nameArray[i],
                    MyData.versionArray[i],
                    MyData.id_[i],
                    MyData.drawableArray[i]
            ));
        }

        removedItems = new ArrayList();

        adapter = new CustomAdapter(data);
        recyclerView.setAdapter(adapter);
    }


    private static class MyOnClickListener implements View.OnClickListener {

        private final Context context;

        private MyOnClickListener(Context context) {
            this.context = context;
        }

        @Override
        public void onClick(View v) {
            removeItem(v);
        }

        private void removeItem(View v) {
            int selectedItemPosition = recyclerView.getChildPosition(v);
            RecyclerView.ViewHolder viewHolder
                    = recyclerView.findViewHolderForPosition(selectedItemPosition);
            TextView textViewName
                    = (TextView) viewHolder.itemView.findViewById(R.id.textViewName);
            String selectedName = (String) textViewName.getText();
            int selectedItemId = -1;
            for (int i = 0; i < MyData.nameArray.length; i++) {
                if (selectedName.equals(MyData.nameArray[i])) {
                    selectedItemId = MyData.id_[i];
                }
            }
            removedItems.add(selectedItemId);
            data.remove(selectedItemPosition);
            adapter.notifyItemRemoved(selectedItemPosition);
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        super.onCreateOptionsMenu(menu);
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        super.onOptionsItemSelected(item);
        if (item.getItemId() == R.id.add_item) {
           //проверить, есть ли элементы для добавления
            if (removedItems.size() != 0) {
                addRemovedItemToList();
            } else {
                Toast.makeText(this, "Nothing to add", Toast.LENGTH_SHORT).show();
            }
        }
        return true;
    }

    private void addRemovedItemToList() {
        int addItemAtListPosition = 3;
        data.add(addItemAtListPosition, new DataModel(
                MyData.nameArray[removedItems.get(0)],
                MyData.versionArray[removedItems.get(0)],
                MyData.id_[removedItems.get(0)],
                MyData.drawableArray[removedItems.get(0)]
        ));
        adapter.notifyItemInserted(addItemAtListPosition);
        removedItems.remove(0);
    }
}

Следующий код демонстрирует использование метода removeItems(), который вызывается из метода слушателя для удаления выбранного CardView. Его соответствующий идентификатор сохраняется в массиве для последующего извлечения. Для добавления представления позже мы реализовали еще один метод с именем addRemovedItemToList(). В этом методе мы добавляем представление на предопределенную позицию в списке и удаляем его идентификатор из массива removedItems. CustomAdapter уведомляется в обоих случаях. Класс CustomeAdapter.java определен ниже :

package com.journaldev.recyclerviewcardview;

import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

import java.util.ArrayList;

public class CustomAdapter extends RecyclerView.Adapter<CustomAdapter.MyViewHolder> {

    private ArrayList<DataModel> dataSet;

    public static class MyViewHolder extends RecyclerView.ViewHolder {

        TextView textViewName;
        TextView textViewVersion;
        ImageView imageViewIcon;

        public MyViewHolder(View itemView) {
            super(itemView);
            this.textViewName = (TextView) itemView.findViewById(R.id.textViewName);
            this.textViewVersion = (TextView) itemView.findViewById(R.id.textViewVersion);
            this.imageViewIcon = (ImageView) itemView.findViewById(R.id.imageView);
        }
    }

    public CustomAdapter(ArrayList<DataModel> data) {
        this.dataSet = data;
    }

    @Override
    public MyViewHolder onCreateViewHolder(ViewGroup parent,
                                           int viewType) {
        View view = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.cards_layout, parent, false);

        view.setOnClickListener(MainActivity.myOnClickListener);

        MyViewHolder myViewHolder = new MyViewHolder(view);
        return myViewHolder;
    }

    @Override
    public void onBindViewHolder(final MyViewHolder holder, final int listPosition) {

        TextView textViewName = holder.textViewName;
        TextView textViewVersion = holder.textViewVersion;
        ImageView imageView = holder.imageViewIcon;

        textViewName.setText(dataSet.get(listPosition).getName());
        textViewVersion.setText(dataSet.get(listPosition).getVersion());
        imageView.setImageResource(dataSet.get(listPosition).getImage());
    }

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

В приведенном выше коде мы реализовали собственный ViewHolder, расширяя RecyclerView.ViewHolder. Представление надувается из cards_layout.xml, который мы определили в каталоге макетов. Обработчик щелчка в MainActivity привязан к этому представлению в следующем отрывке кода.

view.setOnClickListener(MainActivity.myOnClickListener);

ArrayList хранит все данные в форме объекта класса DataModel в ArrayList и добавляет их к соответствующим картам в списке. Классы DataModel.java и MyData.java, содержащие данные, специфичные для этого приложения, приведены ниже:

package com.journaldev.recyclerviewcardview;

public class DataModel {

    String name;
    String version;
    int id_;
    int image;

    public DataModel(String name, String version, int id_, int image) {
        this.name = name;
        this.version = version;
        this.id_ = id_;
        this.image=image;
    }

    public String getName() {
        return name;
    }

    public String getVersion() {
        return version;
    }

    public int getImage() {
        return image;
    }

    public int getId() {
        return id_;
    }
}
package com.journaldev.recyclerviewcardview;

public class MyData {

    static String[] nameArray = {"Cupcake", "Donut", "Eclair", "Froyo", "Gingerbread", "Honeycomb", "Ice Cream Sandwich","JellyBean", "Kitkat", "Lollipop", "Marshmallow"};
    static String[] versionArray = {"1.5", "1.6", "2.0-2.1", "2.2-2.2.3", "2.3-2.3.7", "3.0-3.2.6", "4.0-4.0.4", "4.1-4.3.1", "4.4-4.4.4", "5.0-5.1.1","6.0-6.0.1"};

    static Integer[] drawableArray = {R.drawable.cupcake, R.drawable.donut, R.drawable.eclair,
            R.drawable.froyo, R.drawable.gingerbread, R.drawable.honeycomb, R.drawable.ics,
            R.drawable.jellybean, R.drawable.kitkat, R.drawable.lollipop,R.drawable.marsh};

    static Integer[] id_ = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
}

Ниже приведен результат работы нашего приложения-примера с использованием RecyclerView и CardView для Android. Как видно, удаленный элемент всегда добавляется на третий индекс (четвертое положение в списке). Этим завершается данное руководство по использованию RecyclerView и CardView для Android. Вы можете скачать Проект-пример Android RecyclerView CardView по следующей ссылке.

Скачать Пример проекта Android RecyclerView CardView

Source:
https://www.digitalocean.com/community/tutorials/android-recyclerview-android-cardview-example-tutorial