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 по следующей ссылке.