Статьи

Руководство по Android Recycler и CardView

Новая библиотека поддержки в Android L (Lollipop) представила два новых виджета пользовательского интерфейса: RecyclerView и CardView . RecyclerView — это более продвинутая и более гибкая версия ListView. Этот новый компонент — большой шаг, потому что ListView — один из наиболее часто используемых виджетов пользовательского интерфейса. Виджет CardView, с другой стороны, является новым компонентом, который не «обновляет» существующий компонент. В этом уроке я объясню, как использовать эти два виджета, и покажу, как мы можем их смешивать. Давайте начнем с погружения в RecyclerView.

Темы охватывали

  • RecyclerView
  • CardView
  • Android-адаптер

RecyclerView: Введение

Как я уже говорил, RecyclerView является более гибким, чем ListView, даже если он представляет некоторые сложности, Мы все знаем, как использовать ListView в нашем приложении, и мы знаем, что если мы хотим увеличить производительность ListView, мы можем использовать шаблон под названием ViewHolder. Этот шаблон состоит из простого класса, который содержит ссылки на компоненты пользовательского интерфейса для каждой строки в ListView. Этот шаблон избегает поиска компонентов пользовательского интерфейса все время, пока система показывает строку в списке. Даже если этот шаблон вводит некоторые преимущества, мы можем реализовать ListView, не используя его вообще. RecyclerView заставляет нас использовать шаблон ViewHolder. Чтобы показать, как мы можем использовать RecyclerView, мы можем предположить, что мы хотим создать простое приложение, которое показывает список карточек контактов. Первое, что мы должны сделать, это создать основной макет. RecyclerView очень похож на ListView, и мы можем использовать их таким же образом:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
                xmlns:tools="http://schemas.android.com/tools"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:paddingLeft="@dimen/activity_horizontal_margin" 
                android:paddingRight="@dimen/activity_horizontal_margin"
                android:paddingTop="@dimen/activity_vertical_margin"
                android:paddingBottom="@dimen/activity_vertical_margin"
                tools:context=".MyActivity">
   <android.support.v7.widget.RecyclerView
             android:id="@+id/cardList"
             android:layout_width="match_parent"
             android:layout_height="match_parent"/>
</RelativeLayout>

Как вы заметите из макета, показанного выше, RecyclerView доступен в библиотеке поддержки Android, поэтому мы должны изменить build.gradle, чтобы включить эту зависимость:

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

}
<a name="more"></a>

Теперь в методе onCreate мы можем получить ссылку на наш RecyclerView и настроить его:

@Override
protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_my);
        RecyclerView recList = (RecyclerView) findViewById(R.id.cardList);
        recList.setHasFixedSize(true);
        LinearLayoutManager llm = new LinearLayoutManager(this);
        llm.setOrientation(LinearLayoutManager.VERTICAL);
        recList.setLayoutManager(llm);
}

Если вы посмотрите на код выше, вы заметите некоторые различия между RecyclerView и ListView. RecyclerView требует менеджера по расположению. Этот компонент размещает представления элементов внутри строки и определяет, когда пришло время перерабатывать представления. Библиотека предоставляет менеджер макетов по умолчанию под названием LinearLayoutManager.

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

<android.support.v7.widget.CardView
         xmlns:card_view="http://schemas.android.com/apk/res-auto"
         xmlns:android="http://schemas.android.com/apk/res/android"
         android:id="@+id/card_view"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         card_view:cardCornerRadius="4dp"
         android:layout_margin="5dp">
   <RelativeLayout
          android:layout_width="match_parent"
          android:layout_height="match_parent">
       <TextView
          android:id="@+id/title"
          android:layout_width="match_parent"
          android:layout_height="20dp"
          android:background="@color/bkg_card"
          android:text="contact det"
          android:gravity="center_vertical"
          android:textColor="@android:color/white"
          android:textSize="14dp"/>
      <TextView
          android:id="@+id/txtName"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:text="Name"
          android:gravity="center_vertical"
          android:textSize="10dp"
          android:layout_below="@id/title"
          android:layout_marginTop="10dp"
          android:layout_marginLeft="5dp"/>
      <TextView
          android:id="@+id/txtSurname"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:text="Surname"
          android:gravity="center_vertical"
          android:textSize="10dp"
          android:layout_below="@id/txtName"
          android:layout_marginTop="10dp"
          android:layout_marginLeft="5dp"/>
      <TextView
          android:id="@+id/txtEmail"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:text="Email"
          android:textSize="10dp"
          android:layout_marginTop="10dp"
          android:layout_alignParentRight="true"
          android:layout_marginRight="150dp"
          android:layout_alignBaseline="@id/txtName"/>
</RelativeLayout>

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

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

RecyclerView: адаптер

Адаптер — это компонент, который стоит между моделью данных, которую мы хотим показать в пользовательском интерфейсе приложения, и компонентом интерфейса, который отображает эту информацию. Другими словами, адаптер определяет способ отображения информации в пользовательском интерфейсе. Поэтому, если мы хотим отобразить наши контакты, нам нужен адаптер для RecyclerView. Этот адаптер должен расширять класс с именем RecyclerView.Adapter, передавая наш класс, который реализует шаблон ViewHolder:

public class MyAdapter extends RecyclerView.Adapter<MyHolder> { ..... }

Теперь нам нужно переопределить два метода, чтобы мы могли реализовать нашу логику: onCreateViewHolder вызывается всякий раз, когда создается новый экземпляр нашего класса ViewHolder, и onBindViewHolder вызывается, когда SO связывает представление с данными — или, другими словами, данные отображаются в пользовательском интерфейсе. В этом случае адаптер помогает нам объединить RecyclerView и CardView. Макет, который мы определили ранее для карточек, будет макетом строки нашего списка контактов в RecyclerView. Прежде чем сделать это, мы должны определить нашу модель данных, которая лежит в основе нашего пользовательского интерфейса (т.е. какую информацию мы хотим показать). Для этого мы можем определить простой класс:

public class ContactInfo {
    protected String name;
    protected String surname;
    protected String email;
    protected static final String NAME_PREFIX = "Name_";
    protected static final String SURNAME_PREFIX = "Surname_";
    protected static final String EMAIL_PREFIX = "email_";
}

И, наконец, мы готовы создать наш адаптер. Если вы помните, что мы говорили ранее о шаблоне Viewholder, мы должны написать наш класс, который реализует его:

public static class ContactViewHolder extends RecyclerView.ViewHolder {
    protected TextView vName;
    protected TextView vSurname;
    protected TextView vEmail;
    protected TextView vTitle;

    public ContactViewHolder(View v) {
       super(v);
       vName =  (TextView) v.findViewById(R.id.txtName);
       vSurname = (TextView)  v.findViewById(R.id.txtSurname);
       vEmail = (TextView)  v.findViewById(R.id.txtEmail);
       vTitle = (TextView) v.findViewById(R.id.title);
    }
}

Посмотрите на код, в конструкторе класса мы получаем ссылку на представления, которые мы определили в макете нашей карты. Теперь пришло время кодировать наш адаптер:

public class ContactAdapter extends 
              RecyclerView.Adapter<ContactAdapter.ContactViewHolder> {

              private List<ContactInfo> contactList;

              public ContactAdapter(List<ContactInfo> contactList) {
                 this.contactList = contactList;
              }

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

             @Override
             public void onBindViewHolder(ContactViewHolder contactViewHolder, int i) {
                 ContactInfo ci = contactList.get(i);
                 contactViewHolder.vName.setText(ci.name);
                 contactViewHolder.vSurname.setText(ci.surname);
                 contactViewHolder.vEmail.setText(ci.email);
                 contactViewHolder.vTitle.setText(ci.name + " " + ci.surname);
             }

            @Override
            public ContactViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
              View itemView = LayoutInflater.from(viewGroup.getContext()).
              inflate(R.layout.card_layout, viewGroup, false);
              return new ContactViewHolder(itemView);
            }

            public static class ContactViewHolder extends RecyclerView.ViewHolder {
              ...
            }
}

В нашей реализации мы переопределяем onBindViewHolder, где привязываем данные (наши контактные данные) к представлениям. Обратите внимание, что мы не ищем компоненты пользовательского интерфейса, а просто используем ссылки, хранящиеся в нашем ContactViewHolder. В onCreateViewHolder мы возвращаем наш ContactViewHolder с надувным макетом строки (в нашем случае CardView). Запустите приложение, и вы получите результаты, показанные ниже: