T.M. SoftStudio

feci quod potui, faciant meliora potentes

Android Design Support Library

Android-5,0 Lollipop это один из самых значимых релизов Android когда-либо, в немалой степени из-за введения дизайна материалов - нового языка дизайна, который освежил весь опыт Android. С небольшой помощью Android Design Support Library библиотеки, обеспечивается ряд важных компонентов дизайна материалов для всех разработчиков и для всех Android 2.1 или выше устройств. Это navigation drawer view, плавающая метка для редактируемого текста, floating action button, snackbar, tabs, фреймворк motion and scroll framework, чтобы связать их вместе.

Navigation drawer view
Navigation drawer view может быть важным координационным центром для идентификации и навигации в вашем приложении и непротиворечивости в дизайне, он может значительно улучшить то, как легко ваше приложение предназначено для навигации, особенно для начинающих пользователей. NavigationView делает это проще, предоставляя основу, которая необходима для navigation drawer, а также способность раздувать навигационные элементы с помощью ресурса меню.
<android.support.v4.widget.DrawerLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fitsSystemWindows="true">

    <!-- your content layout -->

    <android.support.design.widget.NavigationView
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_gravity="start"
            app:headerLayout="@layout/drawer_header"
            app:menu="@menu/drawer"/>
</android.support.v4.widget.DrawerLayout>

Два атрибута для NavigationView: 

app:headerLayout: контролирует (по желанию) макет, используемый для заголовка.

app:menu это ресурс меню для навигационных элементов (которые также могут быть обновлены во время выполнения).

Простейшее меню - коллекция отмечаемых пунктов меню:

<group android:checkableBehavior="single">
    <item
        android:id="@+id/navigation_item_1"
        android:checked="true"
        android:icon="@drawable/ic_android"
        android:title="@string/navigation_item_1"/>
    <item
        android:id="@+id/navigation_item_2"
        android:icon="@drawable/ic_android"
        android:title="@string/navigation_item_2"/>
</group>

 

Вы также можете разделить меню на отдельные группы элементов:

<item
    android:id="@+id/navigation_subheader"
    android:title="@string/navigation_subheader">
    <menu>
        <item
            android:id="@+id/navigation_sub_item_1"
            android:icon="@drawable/ic_android"
            android:title="@string/navigation_sub_item_1"/>
        <item
            android:id="@+id/navigation_sub_item_2"
            android:icon="@drawable/ic_android"
            android:title="@string/navigation_sub_item_2"/>
    </menu>
</item>
Плавающие метки для редактируемого текста
 
Даже скромный EditText может быть местом для улучшения дизайна материалов.
В то время как EditText будет скрывать текст подсказки при наборе первого символа, теперь вы можете обернуть его в TextInputLayout, в результате чего текст подсказки станет плавающей меткой над EditText, гарантируя, что пользователи никогда не потеряют контекст.
В дополнение к показу подсказки, вы также можете отобразить сообщение об ошибке ниже EditText вызвав setError().
 
Floating Action Button

Плавающая кнопка действия это круглая кнопка, обозначающая первичное действие интерфейса. FloatingActionButton библиотеки дает вам одну последовательную реализацию, с цветом по умолчанию, используя colorAccent вашей темы.

В дополнение к нормальному размеру плавающей кнопки действий, также поддерживается мини-размер (fabSize = "мини"), когда визуальная непрерывность с другими элементами является критической.

Так как FloatingActionButton расширяет ImageView, можно использовать android:src  или любой из методов, таких как setImageDrawable() для установки значка, показываемого в FloatingActionButton.

Snackbar

Для предоставление легкого, быстрого отзыва операции, прекрасная возможность использовать snackbar. Snackbars  показываются в нижней части экрана и содержат текст с необязательным действием. Они имеют автоматический тайм-аут после заданного времени анимации экрана. Кроме того, пользователи могут убрать их прочь, не ожидая тайм-аут.

Snackbar
  .make(parentLayout, R.string.snackbar_text, Snackbar.LENGTH_LONG)
  .setAction(R.string.snackbar_action, myOnClickListener)
  .show(); // Don’t forget to show!

Tabs

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

TabLayout библиотеки реализует как фиксированные вкладки, где ширина вида делится поровну между всеми вкладками, а также прокручивающиеся вкладки, где вкладки не имеют однородного размера и могут прокручиваться по горизонтали. Вкладки могут быть добавлены программно:

TabLayout tabLayout = ...;
tabLayout.addTab(tabLayout.newTab().setText("Tab 1"));

Однако, если вы используете ViewPager для горизонтального переключения вкладок, вы можете создать вкладки непосредственно из вашего getPageTitle PagerAdapter, а затем соединить их вместе с помощью setupWithViewPager(). Это гарантирует обновление ViewPager.

CoordinatorLayout, движение и прокрутка
 
Различные визуализации это только одна часть дизайна материалов: движение также является важной частью создания материала, предназначенного приложению. В то время как есть много видов движения в дизайне материалов, в том числе сенсорная рябь и значимые переходы, библиотека дизайна вводит CoordinatorLayout, макет, который обеспечивает дополнительный уровень контроля над сенсорными событиями между дочерними видами.
 
CoordinatorLayout и плавающие кнопки действий
 
Отличный пример это когда вы добавляете FloatingActionButton как дочерний лемент вашего CoordinatorLayout, а затем передаете этот CoordinatorLayout методу Snackbar.make().
При этом FloatingActionButton автоматически двигается вверх, когда snackbar  появляется и возвращается в прежнее положение, когда snackbar  исчезает на Android 3.0 и выше устройствах - без дополнительного кода.

CoordinatorLayout также предоставляет атрибут layout_anchor, который, наряду с layout_anchorGravity, может быть использован для размещения плавающих видов, таких как FloatingActionButton, по отношению к другим видам.

CoordinatorLayout и app bar

Другой основной вариант использования для CoordinatorLayout касается бара приложения (ранее  action bar) и техник прокрутки. Вы, возможно, уже использовали панель инструментов Toolbar в макете, которая позволяет более легко настроить внешний вид и интеграцию этой знаменитой части приложения с остальной частью макета. Библиотека дизайна поднимает это на следующий уровень: с помощью AppBarLayout позволяет панели инструментов и другим видам (например, вкладкам, предусмотренных TabLayout) реагировать на события прокрутки в одноуровневом виде с помощью ScrollingViewBehavior. Поэтому вы можете создать макет, такой как:

<android.support.design.widget.CoordinatorLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
     
     <! -- Your Scrollable View -->
    <android.support.v7.widget.RecyclerView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layout_behavior="@string/appbar_scrolling_view_behavior" />

    <android.support.design.widget.AppBarLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">
   <android.support.v7.widget.Toolbar
                  ...
                  app:layout_scrollFlags="scroll|enterAlways">

        <android.support.design.widget.TabLayout
                  ...
                  app:layout_scrollFlags="scroll|enterAlways">
     </android.support.design.widget.AppBarLayout>
</android.support.design.widget.CoordinatorLayout>
Теперь, когда пользователь прокручивает RecyclerView, тогда AppBarLayout может реагировать на эти события, используя флаги прокрутки, чтобы управлять прокруткой. Флаги включают в себя:
 
scroll: этот флаг должен быть установлен для всех представлений, которые хотят прокрутиться  от экрана- для представлений, которые не используют этот флаг, они остаются прижаты к верхней части экрана
enterAlways: этот флаг гарантирует, что любая прокрутка вниз вызовет этот вид, чтобы он стал видимым
enterAlwaysCollapsed: когда ваш вид объявил MinHeight и вы используете этот флаг, ваш вид будет минимальной высоты, вновь расширяясь до полной высоты, когда прокрутка достигнет верха.
exitUntilCollapsed: этот флаг вызывает вид для прокрутки от экрана, пока он не "свернут" (MinHeight) перед выходом
Одно замечание: все виды, использующие флаг scroll должны быть объявлены до видов, не использующих этот флаг. Это гарантирует, что все виды выйдут сверху, оставив позади неподвижные элементы.
 
Collapsing Toolbars

Добавление панели инструментов непосредственно к AppBarLayout дает вам доступ к флагам прокрутки enterAlwaysCollapsed и exitUntilCollapsed, но не детальный контроль над тем, как разные элементы реагируют на коллапсинг. Для этого, вы можете использовать CollapsingToolbarLayout:

<android.support.design.widget.AppBarLayout
        android:layout_height="192dp"
        android:layout_width="match_parent">
    <android.support.design.widget.CollapsingToolbarLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layout_scrollFlags="scroll|exitUntilCollapsed">
        <android.support.v7.widget.Toolbar
                android:layout_height="?attr/actionBarSize"
                android:layout_width="match_parent"
                app:layout_collapseMode="pin"/>
        </android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>

Эта установка использует CollapsingToolbarLayout app:layout_collapseMode="pin", чтобы убедиться, что Toolbar остается на верхней части экрана в то время как вид коллапсирует. Еще лучше, если вы используете CollapsingToolbarLayout и панель инструментов вместе, название будет автоматически появляться больше, когда макет виден полностью. Обратите внимание, что в этих случаях вам следует вызвать setTitle() в CollapsingToolbarLayout, а не в самой панели инструментов.

В дополнение к прижатому вид, вы можете использовать app:layout_collapseMode="parallax"  (и, возможно, app:layout_collapseParallaxMultiplier="0.7", чтобы установить множитель параллакса) чтобы осуществлять прокрутку параллакса (скажем ImageView в пределах CollapsingToolbarLayout). Этот вариант использования пары будет красивым с  app:contentScrim="?attr/colorPrimary" атрибутом для CollapsingToolbarLayout.

CoordinatorLayout и пользовательские представления
 
Одна вещь, которую важно отметить, что CoordinatorLayout не имеет никакого встроенного понимания поведения FloatingActionButton или AppBarLayout - это обеспечивает дополнительный API в виде Coordinator.Behavior, что позволяет дочерним представленияч лучше контролировать сенсорные события и жесты а также объявить зависимости друг с другом и принимать обратные вызовы с помощью onDependentViewChanged().
 
Представления могут объявить поведение по умолчанию с помощью CoordinatorLayout.DefaultBehavior (YourView.Behavior.class) аннотации, или установить его в файлах макета с помощью app:layout_behavior="com.example.app.YourView$Behavior". Эта структура позволяет для любого вида интеграцию с CoordinatorLayout.
 
ToolBar
 
ToolBar был введен в Android Lollipop, API 21 и полностью заменил для ActionBar. Это ViewGroup так что вы можете разместить его в любом месте в макете. Панель инструментов также обеспечивает больший контроль для настройке его внешнего вида.
 
ToolBar хорошо работает с приложениями, ориентированными на API 21 и выше. Тем не менее, Android обновил библиотеки поддержки AppCompat, поэтому ToolBar можно использовать на более ранних устройствах Android OS. В AppCompat, панель инструментов реализована в классе android.support.v7.widget.Toolbar.
 
Есть два способа использовать панель инструментов
 
Используйте панель инструментов в качестве Action Bar, когда вы хотите использовать существующие Action Bar средства (например, меню и выбор, ActionBarDrawerToggle, и так далее), но хотите иметь больший контроль над внешним видом.
 
Используйте автономную панель инструментов, если вы хотите использовать шаблон в вашем приложении для ситуаций, которые Action Bar не поддерживает; например, показывать несколько панелей на экране, охватывающие только часть ширины, и так далее.
 
Панель инструментов, как ActionBar
 
Чтобы использовать панель инструментов в качестве ActionBar, сначала убедитесь, что библиотека поддержки AppCompat-v7 будет добавлена в файл build.gradle приложения.
dependencies {
  compile fileTree(dir: 'libs', include: ['*.jar'])
  compile 'com.android.support:appcompat-v7:22.2.1+'
}

Во-вторых, нужно отключить тему, предоставляемую ActionBar. Самый простой способ, чтобы ваша тема наследовала от Theme.AppCompat.NoActionBar в styles.xml файла.

<resources>
  <!-- Base application theme. -->
  <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
  </style>
</resources>

Теперь вы должны добавить панель инструментов в файл макета активности. Одно из самых больших преимуществ использования виджета панели инструментов это то, что вы можете разместить его в любом месте в макете. Ниже он расположен в верхней части LinearLayout, как стандартный ActionBar.

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <android.support.v7.widget.Toolbar
      android:id="@+id/toolbar"
      android:minHeight="?attr/actionBarSize"  
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:background="?attr/colorPrimary">
    </android.support.v7.widget.Toolbar>

    ...

</LinearLayout>
Так как Toolbar это просто ViewGroup, он может быть стилизован и расположен как и любой другой вид.
Затем в активнности или фрагменте, установите панель инструментов в качестве ActionBar с помощью метода setSupportActionBar (Toolbar).
Примечание: При использовании библиотеки поддержки, убедитесь, что вы импортируете android.support.v7.widget.Toolbar а не android.widget.Toolbar.
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;

public class MyActivity extends AppCompatActivity {

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

    // Set a ToolBar to replace the ActionBar.
    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);
  }
}

Все пункты меню отображаются в панели инструментов, населенной с помощью стандартных функций обратного вызова меню опций.

Floating Action Button

Плавающие кнопки действий (или FAB) это: "Особый случай продвигаемых действий. Они отличаются в кружке значок плавающей над UI и специальные движения поведения, связанные с морфинга, запуск, и его передачи опорную точку ".
 
Например, если мы используем электронный приложение, и мы листинг в папку Входящие, продвигаемый действие может быть создании нового сообщения.
 
Теперь вы должны добавить вид android.support.design.widget.FloatingActionButton в макет. Атрибут SRC ссылается на значок, который должен быть использован для плавающего действия.
<android.support.design.widget.FloatingActionButton
        android:src="@drawable/ic_done"
        app:fabSize="normal"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
Кроме того, предпологая, что xmlns:app="http://schemas.android.com/apk/res-auto объявлено как пространство имен в верхней части макета, вы также можете определить пользовательский атрибут fabSize - должна ли быть кнопка нормальная или мини.
 
Чтобы разместить кнопку плавающего действия, вы будете использовать CoordinatorLayout.
 
CoordinatorLayout помогает облегчить взаимодействие между видами, содержащихся в нем, будет полезен в дальнейшем для описания, как анимировать кнопку в зависимости от изменений прокрутки. Сейчас мы можем воспользоваться функцией в CoordinatorLayout, которая позволяет нам накладывать один элемент над другим. Мы просто должны иметь ListView и FloatingActionButton содержащуюся в CoordinatorLayout и использовать атрибуты layout_anchor и layout_anchorGravity.
<android.support.design.widget.CoordinatorLayout
    android:id="@+id/main_content"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

          <ListView
              android:id="@+id/lvToDoList"
              android:layout_width="match_parent"
              android:layout_height="match_parent"></ListView>

          <android.support.design.widget.FloatingActionButton
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:layout_gravity="bottom|right"
              android:layout_margin="16dp"
              android:src="@drawable/ic_done"
              app:layout_anchor="@id/lvToDoList"
              app:layout_anchorGravity="bottom|right|end" />

</android.support.design.widget.CoordinatorLayout>
Кнопка должна быть помещена в нижнем правом углу экрана. Рекомендуется нижний отступ 16DP для телефонов и 24dp для планшетов. В приведенном выше примере, был использован 16DP.
 
Когда пользователь прокручивает страницу вниз, кнопка плавающего действия должна исчезнуть. После того, как страница прокручивается вверх, она должна появиться.
 
Чтобы анимировать эту часть, вам нужно будет воспользоваться CoordinatorLayout, который помогает хореографии анимации между видами, определенными в этой схеме.
 
Преобразование из списка в RecyclerView
 
В настоящее время, вам нужно конвертировать ваши ListViews в RecyclerView. RecyclerView является преемником ListView.
<android.support.v7.widget.RecyclerView
         android:id="@+id/lvToDoList"
         android:layout_width="match_parent"
         android:layout_height="match_parent">
</android.support.v7.widget.RecyclerView>
Далее, вы должны реализовать CoordinatorLayout Behavior для кнопки действий. Этот класс будет использоваться для определения того, как кнопка должна реагировать на другие виды, содержащихся в том же CoordinatorLayout.
 

 

Создайте файл с именем ScrollAwareFABBehavior.java, который расширяет FloatingActionButton.Behavior. В настоящее время, поведение по умолчанию используется для Floating Action Button чтобы освободить место для Snackbar. Мы хотим расширить это поведение, чтобы сигнализировать, что мы хотим обработать событие прокрутки в вертикальном направлении:
public class ScrollAwareFABBehavior extends FloatingActionButton.Behavior {

    @Override
    public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout,
            FloatingActionButton child, View directTargetChild, View target, int nestedScrollAxes) {
        return nestedScrollAxes == ViewCompat.SCROLL_AXIS_VERTICAL || 
            super.onStartNestedScroll(coordinatorLayout, child, directTargetChild, target,
            nestedScrollAxes);
    }

}
Так как прокрутка будет обрабатываться этим классом, отдельный метод onNestedScroll() будет вызван. Мы можем проверить положение Y и определить анимацию кнопки.

 

Благодаря недавней модернизации библиотеки поддержки v4, есть также методы show() and hide(), которые выполняют плавное и постепенное исчезновение плавающей кнопки действия.
public class ScrollAwareFABBehavior extends FloatingActionButton.Behavior {
    // ...

    @Override
    public void onNestedScroll(CoordinatorLayout coordinatorLayout, FloatingActionButton child,
            View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
        super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed,
                dyUnconsumed);

        if (dyConsumed > 0 && child.getVisibility() == View.VISIBLE) {
            child.hide();
        } else if (dyConsumed < 0 && child.getVisibility() != View.VISIBLE) {
            child.show();
        }
    }

    // ...
}

Заключительный шаг, чтобы связать CoordinatorLayout Behavior с кнопкой действий, Мы можем определить в декларации XML в качестве пользовательского атрибута app:layout_behavior:

<android.support.design.widget.FloatingActionButton    
    app:layout_behavior="com.codepath.floatingactionbuttontest.ScrollAwareFABBehavior" />

Так как мы определяем это поведение статически в XML, мы должны также реализовать конструктор для того, чтобы макет работал правильно.

public class ScrollAwareFABBehavior extends FloatingActionButton.Behavior {
    // ...

    public ScrollAwareFABBehavior(Context context, AttributeSet attrs) {
        super();
    }

   // ...
}
RecyclerView это новый ViewGroup, который готов отобразить любой вид основанный на адаптере.
 
Он должен быть преемником ListView и GridView.
 
Одной из причин является то, что RecyclerView имеет более расширяемую инфраструктуру, особенно, так как это дает возможность реализовывать горизонтальные и вертикальные макеты. С помощью виджета RecyclerView, когда у вас есть коллекции данных, чьи элементы изменяются во время выполнения на основе действий пользователя или сетевых событий.
 
Если вы хотите использовать RecyclerView, вам нужно будет работать со следующим:
 
RecyclerView.Adapter - для обработки сбора данных и связывания его с видом
 
LayoutManager - помогает в позиционировании элементов
 
ItemAnimator - помогает при анимации элементов для общих операций, таких как добавление или удаление элемента
 
Кроме того, он обеспечивает поддержку анимации для элементов ListView, когда они добавляются или удаляются, что было чрезвычайно трудно сделать в текущей реализации. RecyclerView также применяет шаблон ViewHolder.
 
По сравнению с ListView
 
RecyclerView отличается от своего предшественника ListView в первую очередь следующими функциями:
 
Требование ViewHolder в адаптерах - ListView адаптеры не требуют использования шаблона ViewHolder для повышения производительности. В противоположность этому, реализация адаптера для RecyclerView требует использования шаблона ViewHolder.
 
Настраиваемые макеты элементов - ListView может иметь только макет элементов в вертикальном линейном расположении и это не может быть изменено. В отличие от этого, RecyclerView имеет RecyclerView.LayoutManager, что позволяет любую компоновку элементов, в том числе горизонтальные списки или в шахматном порядке решетки.
 
Легкая анимация элементов - ListView не содержит специальных положений, через которые можно анимировать дополнение или удаление элементов. В противоположность этому, RecyclerView имеет класс RecyclerView.ItemAnimator для обработки анимации элементов.
 
Управление источником данных - ListView имел адаптеры для различных источников, таких как ArrayAdapter и CursorAdapter для массивов и баз данных соответственно. В противоположность этому, RecyclerView.Adapter требует пользовательской реализации для поставки данных к адаптеру.
 
Управление декорированием элементов - ListView имеет android:divider свойство для простых делителей между элементами в списке. В отличие от этого, RecyclerView требует использование объекта RecyclerView.ItemDecoration для установки разделителя.
 
Управление обнаружением кликов - ListView имеет интерфейс AdapterView.OnItemClickListener для связывания с событием щелчка для отдельных элементов в списке. В противоположность этому, RecyclerView имеет поддержку RecyclerView.OnItemTouchListener которая управляет индивидуальными сенсорными событиями, но не имеет встроенной обработки щелчка.
 
Компоненты RecyclerView
 
LayoutManagers
 
RecyclerView необходимо иметь менеджер компоновки и адаптер для инициализации. Менеджер компоновки позиционирует виды пунктов внутри RecyclerView и определяет, когда повторно использовать виды элементов, которые больше не видны пользователю.
 
RecyclerView предоставляет эти встроенные менеджеры компоновки:
 
LinearLayoutManager показывает элементы в вертикальном или горизонтальном списке прокрутки.
GridLayoutManager показывает элементы в виде сетки.
StaggeredGridLayoutManager показывает элементы в шахматной сетке.
Чтобы создать пользовательский менеджер компоновки, нужно расширить класс RecyclerView.LayoutManager.
 
RecyclerView.Adapter
 
RecyclerView включает в себя новый вид адаптера. Это аналогичный подход, которым вы уже пользовались, но с некоторыми особенностями, такими как необходимый ViewHolder. Вам придется переопределить два основных метода: один для надувания вида и его удерживания, и еще один, чтобы связывать данные в представлении. Первый метод вызывается только тогда, когда мы действительно должны создать новый вид. Нет необходимости проверять, если он перерабатывается.
 
ItemAnimator
 
RecyclerView.ItemAnimator будет анимировать ViewGroup модификации, такие как добавление / удаление / выбор, которые уведомляют адаптер. DefaultItemAnimator может быть использован для основных анимаций.
 
Использование RecyclerView
 
Использование RecyclerView имеет следующие основные этапы:
 
Добавить библиотеку поддержки RecyclerView к Gradle файлу сборки
 
Определить класс модели для использования в качестве источника данных
 
Добавить RecyclerView к вашей активности для отображения элементов
 
Создать пользовательский XML макет строк для визуализации пунктов
 
Создать RecyclerView.Adapter и ViewHolder для отобржения пунктов
 
Привязать адаптер к источнику данных для заполнения RecyclerView
 
Определение модели
 
Каждый RecyclerView опирается на источник данных. В этом случае, мы определим Contact класс, представляющий модель данных для отображения в RecyclerView:
public class Contact {
    private String mName;
    private boolean mOnline;

    public Contact(String name, boolean online) {
        mName = name;
        mOnline = online;
    }

    public String getName() {
        return mName;
    }

    public boolean isOnline() {
        return mOnline;
    }

    private static int lastContactId = 0;

    public static List<Contact> createContactsList(int numContacts) {
        List<Contact> contacts = new ArrayList<Contact>();

        for (int i = 1; i <= numContacts; i++) {
            contacts.add(new Contact("Person " + ++lastContactId, i <= numContacts / 2));
        }

        return contacts;
    }
}
Создать RecyclerView внутри макета
 
Внутри нужной активности в макете XML в res/layout/activity_users.xml, давайте добавим RecyclerView из библиотеки поддержки:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
    
    <android.support.v7.widget.RecyclerView
      android:id="@+id/rvContacts"
      android:layout_width="match_parent"
      android:layout_height="match_parent" />

</RelativeLayout>

Теперь RecyclerView встраивается в нашем макете активности. Далее, мы можем определить макет для каждого элемента в нашем списке.

Прежде, чем мы создадим адаптер, давайте определим файл макета XML, который будет использоваться для каждой строки в списке. Этот макет пунктов здесь должен содержать горизонтальную линейную планировку с TextView для имени и кнопки для сообщения:

Этот файл макета может быть создан в  res/layout/item_contact.xml  и будет отображаться для каждого строки элементов:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:paddingTop="10dp"
        android:paddingBottom="10dp"
        >

    <TextView
        android:id="@+id/contact_name"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        />

    <Button
        android:id="@+id/message_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:paddingLeft="16dp"
        android:paddingRight="16dp"
        android:textSize="10sp"
        />
</LinearLayout>
Создание RecyclerView.Adapter
 
Здесь мы должны создать адаптер, который будет заполнять данные в RecyclerView. Роль адаптера это преобразование объекта в положение в пункте списка для вставки.

 

Однако RecyclerView адаптер требует существование "ViewHolder" объекта, который описывает и обеспечивает доступ ко всем видам в пределах каждого элемента строки. Мы можем создать базовый пустой адаптер и держатель вместе в ContactsAdapter.java следующим образом:
// Create the basic adapter extending from RecyclerView.Adapter
// Note that we specify the custom ViewHolder which gives us access to our views
public class ContactsAdapter extends 
    RecyclerView.Adapter<ContactsAdapter.ViewHolder> {

    // Provide a direct reference to each of the views within a data item
    // Used to cache the views within the item layout for fast access
    public static class ViewHolder extends RecyclerView.ViewHolder {
        // Your holder should contain a member variable
        // for any view that will be set as you render a row
        public TextView nameTextView;
        public Button messageButton;

        // We also create a constructor that accepts the entire item row
        // and does the view lookups to find each subview
        public ViewHolder(View itemView) {
            // Stores the itemView in a public final member variable that can be used
            // to access the context from any ViewHolder instance.
            super(itemView);

            nameTextView = (TextView) itemView.findViewById(R.id.contact_name);
            messageButton = (Button) itemView.findViewById(R.id.message_button);
        }
    }
}

Теперь, когда мы определили основной адаптер и ViewHolder, мы должны начать заполнение в нашем адаптере. Во-первых, давайте хранить переменную-член для списка контактов и передадим список в нашем конструкторе:

public class ContactsAdapter extends 
    RecyclerView.Adapter<ContactsAdapter.ViewHolder> {

    // ... view holder defined above...

    // Store a member variable for the contacts
    private List<Contact> mContacts;

    // Pass in the contact array into the constructor
    public ContactsAdapter(List<Contact> contacts) {
        mContacts = contacts;
    }
}

Каждый адаптер имеет три основных метода: onCreateViewHolder, чтобы раздувать макет пунктов и создать держатель, onBindViewHolder, чтобы установить атрибуты вида на основе данных, и getItemCount, чтобы определить количество элементов. Мы должны реализовать все три, чтобы закончить адаптер:

public class ContactsAdapter extends 
    RecyclerView.Adapter<ContactsAdapter.ViewHolder> {

    // ... constructor and member variables

    // Usually involves inflating a layout from XML and returning the holder
    @Override
    public ContactsAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        Context context = parent.getContext();
        LayoutInflater inflater = LayoutInflater.from(context);

        // Inflate the custom layout
        View contactView = inflater.inflate(R.layout.item_contact, parent, false);

        // Return a new holder instance
        ViewHolder viewHolder = new ViewHolder(contactView);
        return viewHolder;
    }
    
    // Involves populating data into the item through holder
    @Override
    public void onBindViewHolder(ContactsAdapter.ViewHolder viewHolder, int position) {
        // Get the data model based on position
        Contact contact = mContacts.get(position);

        // Set item views based on the data model
        TextView textView = viewHolder.nameTextView;
        textView.setText(contact.getName());

        Button button = viewHolder.messageButton;

        if (contact.isOnline()) {
            button.setText("Message");
            button.setEnabled(true);
        }
        else {
            button.setText("Offline");
            button.setEnabled(false);
        }

    }

    // Return the total count of items
    @Override
    public int getItemCount() {
        return mContacts.size();
    }
}
Привязка адаптера к RecyclerView

 

В нашей активности мы будем заполнять набор пользователей, который должен быть отображен в RecyclerView.
public class UserListActivity extends AppCompatActivity {

     @Override
     protected void onCreate(Bundle savedInstanceState) {
         // ...
         // Lookup the recyclerview in activity layout
         RecyclerView rvContacts = (RecyclerView) findViewById(R.id.rvContacts);
         // Create adapter passing in the sample user data
         ContactsAdapter adapter = new ContactsAdapter(Contact.createContactsList(20));
         // Attach the adapter to the recyclerview to populate items
         rvContacts.setAdapter(adapter);
         // Set layout manager to position the items
         rvContacts.setLayoutManager(new LinearLayoutManager(this));
         // That's all!
     }
}

В отличие от ListView, нет никакого способа, чтобы добавить или удалить элементы непосредственно через адаптер RecyclerView. Вы должны внести изменения в источник данных прямо и уведомить адаптер об изменениях. Есть много методов, которые можно использовать при уведомлении адаптера о различных изменениях.

// Add a new user
users.set(0, new User(...));
// Notify the adapter
adapter.notifyItemInserted(0);

Каждый раз, когда мы хотим добавить или удалить элементы из RecyclerView, нам нужно явно сообщить это адаптеру. В отличие от адаптера ListView, адаптер RecyclerView не должен полагаться на notifyDataSetChanged.

Прокрутка вновь созданных элементов
 
Если мы вставляем элементы в переднюю часть списка, и хотели бы сохранить положение на вершине, мы можем установить позицию прокрутки на 1-й элемент:
 
adapter.notifyItemInserted(0);  
rvContacts.scrollToPosition(0); 

Если мы добавляем элементы в конец и хотим перейти к нижней части, как только элементы будут добавлены, мы можем уведомить адаптер, что дополнительный элемент был добавлен и можем вызвать smoothScrollToPosition() RecyclerView:

adapter.notifyItemInserted(contacts.size() - 1);  // contacts.size() - 1 is the last element position
rvContacts.scrollToPosition(mAdapter.getItemCount() - 1); // update based on adapter 
Настройка RecyclerView
 
RecyclerView является достаточно гибким и настраиваемым. 
 
Производительность
 
Мы также можем включить оптимизацию, если все виды одной и той же высоты и ширины, для плавного скроллинга:
recyclerView.setHasFixedSize(true);

Мы можем украсить элементы, используя различные декораторы, прикрепленные к переработчику, такие как DividerItemDecoration:

RecyclerView.ItemDecoration itemDecoration = new 
    DividerItemDecoration(this, DividerItemDecoration.VERTICAL_LIST);
recyclerView.addItemDecoration(itemDecoration);

Позиционирование элементов настраивается с помощью менеджера компоновки. По умолчанию, мы можем выбирать между LinearLayoutManager, GridLayoutManager и StaggeredGridLayoutManager. Linear отображает элементы вертикально или горизонтально:

// Setup layout manager for items
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
// Control orientation of the items
// also supports LinearLayoutManager.HORIZONTAL
layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
// Optionally customize the position you want to default scroll to
layoutManager.scrollToPosition(0);
// Attach layout manager to the RecyclerView
recyclerView.setLayoutManager(layoutManager);

Отображение элементов в сетке или шахматном порядке работает аналогично:

// First param is number of columns and second param is orientation i.e Vertical or Horizontal
StaggeredGridLayoutManager gridLayoutManager = 
    new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL);
// Attach the layout manager to the recycler view
recyclerView.setLayoutManager(gridLayoutManager);

RecyclerView поддерживает пользовательские анимации для элементов, вхождение, перемещение или удаление. Если вы хотите установить пользовательские анимации, сначала загрузите библиотеку сторонних recyclerview-аниматоров в app/build.gradle:

repositories {
    jcenter()
}

dependencies {
    compile 'jp.wasabeef:recyclerview-animators:1.2.0@aar'
}

Далее, мы можем использовать любой из определенных аниматоров, чтобы изменить поведение нашего RecyclerView:

recyclerView.setItemAnimator(new SlideInUpAnimator());

RecyclerView также может быть использован для надувания несколько типов вида в ситуациях, когда список может быть гетерогенным, в том смысле, что основываясь на ответе от сервера, может быть требование для накачивания различных типов макетов.

Для реализации гетерогенных макетов внутри RecyclerView, большая часть работы делается в RecyclerView.Adapter. В частности, существуют специальные методы, которые будут переопределены в адаптере:
 
getItemViewType ()
onCreateViewHolder ()
onBindViewHolder ()
 
Опираясь на проект использования RecyclerView, мы теперь заменим SimpleItemRecyclerViewAdapter на ComplexRecyclerViewAdapter, который делает всю тяжелую работу, раздувая различные типы макетов в зависимости от типа представления элементов. В следующем примере будет надувать два различных макета на основе объекта, который содержит список. layout_viewholder1.xml будет использоваться для объектов User и layout_viewholder2.xml будет использоваться для объектов String.
 
Для этого упражнения, мы будем изменять наш набор данных в RecyclerViewActivity чтобы содержать список объектов:
private ArrayList<Object> getSampleArrayList() {
      ArrayList<Object> items = new ArrayList<>();
      items.add(new User("Dany Targaryen", "Valyria"));
      items.add(new User("Rob Stark", "Winterfell"));
      items.add("image");
      items.add(new User("Jon Snow", "Castle Black"));
      items.add("image");
      items.add(new User("Tyrion Lanister", "King's Landing"));
      return items;
  }

Далее, вам нужно создать классы (и макеты) для ViewHolder1 (layout_viewholder1.xml) и ViewHolder2 (layout_viewholder2.xml).

ViewHolder1.java

public class ViewHolder1 extends RecyclerView.ViewHolder {

    private TextView label1, label2;

    public ViewHolder1(View v) {
        super(v);
        label1 = (TextView) v.findViewById(R.id.text1);
        label2 = (TextView) v.findViewById(R.id.text2);
    }

    public TextView getLabel1() {
        return label1;
    }

    public void setLabel1(TextView label1) {
        this.label1 = label1;
    }

    public TextView getLabel2() {
        return label2;
    }

    public void setLabel2(TextView label2) {
        this.label2 = label2;
    }
}

layout_viewholder1.xml

 

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/llContainer"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:padding="5dp">

    <TextView
        android:id="@+id/text1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textStyle="bold"
        android:textAppearance="?android:attr/textAppearanceListItemSmall"
        android:gravity="center_vertical"/>

    <TextView
        android:id="@+id/text2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceListItemSmall"
        android:gravity="center_vertical" />

</LinearLayout>

ViewHolder2.java

public class ViewHolder2 extends RecyclerView.ViewHolder {

    private ImageView ivExample;

    public ViewHolder2(View v) {
        super(v);
        ivExample = (ImageView) v.findViewById(R.id.ivExample);
    }

    public ImageView getImageView() {
        return ivExample;
    }

    public void setImageView(ImageView ivExample) {
        this.ivExample = ivExample;
    }
}

layout_viewholder2.xml

 

<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/ivExample"
    android:adjustViewBounds="true"
    android:scaleType="fitXY"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"/>

Создание ComplexRecyclerViewAdapter

public class ComplexRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

    // The items to display in your RecyclerView
    private List<Object> items;

    private final int USER = 0, IMAGE = 1;

    // Provide a suitable constructor (depends on the kind of dataset)
    public ComplexRecyclerViewAdapter(List<Object> items) {
        this.items = items;
    }

    // Return the size of your dataset (invoked by the layout manager)
    @Override
    public int getItemCount() {
        return this.items.size();
    }

    @Override
    public int getItemViewType(int position) {
         //More to come
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
         //More to come
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
         //More to come
    }
}

Теперь, вы должны переопределить метод getItemViewType чтобы рассказать RecyclerView о типе вида чтобы раздуть на основе положения. Мы будем возвращать USER или изображение в зависимости от типа объекта данных.

//Returns the view type of the item at position for the purposes of view recycling.
  @Override
  public int getItemViewType(int position) {
      if (items.get(position) instanceof User) {
          return USER;
      } else if (items.get(position) instanceof String) {
          return IMAGE;
      }
      return -1;
  }

Далее, вам нужно переопределить метод onCreateViewHolder чтобы рассказать RecyclerView.Adapter какой объект RecyclerView.ViewHolder возвращать для создания на основе viewType. Создать ViewHolder1 с layout_viewholder1 для нечетных элементов и ViewHolder2 с layout_viewholder2 для четных.

/**
   * This method creates different RecyclerView.ViewHolder objects based on the item view type.\
   *
   * @param viewGroup ViewGroup container for the item
   * @param viewType type of view to be inflated
   * @return viewHolder to be inflated
   */
  @Override
  public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {

      RecyclerView.ViewHolder viewHolder;
      LayoutInflater inflater = LayoutInflater.from(viewGroup.getContext());

      switch (viewType) {
          case USER:
              View v1 = inflater.inflate(R.layout.layout_viewholder1, viewGroup, false);
              viewHolder = new ViewHolder1(v1);
              break;
          case IMAGE:
              View v2 = inflater.inflate(R.layout.layout_viewholder2, viewGroup, false);
              viewHolder = new ViewHolder2(v2);
              break;
          default:
              View v = inflater.inflate(android.R.layout.simple_list_item_1, viewGroup, false);
              viewHolder = new RecyclerViewSimpleTextViewHolder(v);
              break;
      }
      return viewHolder;
  }

Далее, переопределить метод onBindViewHolder для настройки ViewHolder с данными, которые должны быть отображены. Различают два различных макета и загружают их с образцами текста и изображения.

/**
   * This method internally calls onBindViewHolder(ViewHolder, int) to update the
   * RecyclerView.ViewHolder contents with the item at the given position
   * and also sets up some private fields to be used by RecyclerView.
   *
   * @param viewHolder The type of RecyclerView.ViewHolder to populate
   * @param position Item position in the viewgroup.
   */
  @Override
  public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
      switch (viewHolder.getItemViewType()) {
          case USER:
              ViewHolder1 vh1 = (ViewHolder1) viewHolder;
              configureViewHolder1(vh1, position);
              break;
          case IMAGE:
              ViewHolder2 vh2 = (ViewHolder2) viewHolder;
              configureViewHolder2(vh2);
              break;
          default:
              RecyclerViewSimpleTextViewHolder vh = (RecyclerViewSimpleTextViewHolder) viewHolder;
              configureDefaultViewHolder(vh, position);
              break;
      }
  }

Следующие методы используются для настройки отдельных объектов RecyclerView.ViewHolder:

 private void configureDefaultViewHolder(RecyclerViewSimpleTextViewHolder vh, int position) {
      vh.getLabel().setText((CharSequence) items.get(position));
  }

  private void configureViewHolder1(ViewHolder1 vh1, int position) {
      User user = (User) items.get(position);
      if (user != null) {
          vh1.getLabel1().setText("Name: " + user.name);
          vh1.getLabel2().setText("Hometown: " + user.hometown);
      }
  }

  private void configureViewHolder2(ViewHolder2 vh2) {
      vh2.getImageView().setImageResource(R.drawable.sample_golden_gate);
  }

Последнее и важное изменение, прежде чем вы можете запустить программу, будет изменить метод bindDataToAdapter в нашей RecyclerViewActivity, чтобы установить ComplexRecyclerViewAdapter вместо SimpleItemRecyclerViewAdapter следующим образом:

 private void bindDataToAdapter() {
      // Bind adapter to recycler view object
      recyclerView.setAdapter(new ComplexRecyclerViewAdapter(getSampleArrayList()));
  }

RecyclerView позволяет обрабатывать сенсорные события:

recyclerView.addOnItemTouchListener(new RecyclerView.OnItemTouchListener() {

    @Override
    public void onTouchEvent(RecyclerView recycler, MotionEvent event) {
        // Handle on touch events here
    }

    @Override
    public boolean onInterceptTouchEvent(RecyclerView recycler, MotionEvent event) {
        return false;
    }
    
});

RecyclerView не имеет специальных положений для прикрепления обработчиков кликов к пунктам в отличие от ListView, который имеет метод setOnItemClickListener. Для достижения подобного эффекта, мы можете прикрепить события кликов в ViewHolder в нашем адаптере:

public class ContactsAdapter extends RecyclerView.Adapter<ContactsAdapter.ViewHolder> {
    // ...

    // Used to cache the views within the item layout for fast access
    public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
        public TextView tvName;
        public TextView tvHometown;
        private Context context;

        public ViewHolder(Context context, View itemView) {
            super(itemView);
            this.tvName = (TextView) itemView.findViewById(R.id.tvName);
            this.tvHometown = (TextView) itemView.findViewById(R.id.tvHometown);
            // Store the context
            this.context = context;
            // Attach a click listener to the entire row view
            itemView.setOnClickListener(this);
        }

        // Handles the row being being clicked
        @Override
        public void onClick(View view) {
            int position = getLayoutPosition(); // gets item position
            User user = users.get(position);
            // We can access the data within the views
            Toast.makeText(context, tvName.getText(), Toast.LENGTH_SHORT).show();
        }
    }
    
    // ...
}

Если мы хотим, чтобы пункт показывал "выбранный" эффект при нажатии, мы можем установить android:background корневого макета для ?android:attr/selectableItemBackground:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal" android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="?android:attr/selectableItemBackground"> 
  <!-- ... -->
</LinearLayout>
Прикрепление Click Listeners с Decorators
 
Альтернативное решение для создания обработчиков щелчка для каждого элемента в пределах RecyclerView является использование класса декоратора.
ids.xml
<?xml version="1.0" encoding="utf-8"?>
<!-- You also need to define R.id.item_click_support using ids.xml -->
<resources>
    <item name="item_click_support" type="id" />
</resources>
Raw  ItemClickSupport.java
/*
  Source: http://www.littlerobots.nl/blog/Handle-Android-RecyclerView-Clicks/
  USAGE:
   
  ItemClickSupport.addTo(mRecyclerView).setOnItemClickListener(new ItemClickSupport.OnItemClickListener() {
      @Override
      public void onItemClicked(RecyclerView recyclerView, int position, View v) {
          // do it
      }
  });
*/
public class ItemClickSupport {
    private final RecyclerView mRecyclerView;
    private OnItemClickListener mOnItemClickListener;
    private OnItemLongClickListener mOnItemLongClickListener;
    private View.OnClickListener mOnClickListener = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            if (mOnItemClickListener != null) {
                RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(v);
                mOnItemClickListener.onItemClicked(mRecyclerView, holder.getAdapterPosition(), v);
            }
        }
    };
    private View.OnLongClickListener mOnLongClickListener = new View.OnLongClickListener() {
        @Override
        public boolean onLongClick(View v) {
            if (mOnItemLongClickListener != null) {
                RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(v);
                return mOnItemLongClickListener.onItemLongClicked(mRecyclerView, holder.getAdapterPosition(), v);
            }
            return false;
        }
    };
    private RecyclerView.OnChildAttachStateChangeListener mAttachListener
            = new RecyclerView.OnChildAttachStateChangeListener() {
        @Override
        public void onChildViewAttachedToWindow(View view) {
            if (mOnItemClickListener != null) {
                view.setOnClickListener(mOnClickListener);
            }
            if (mOnItemLongClickListener != null) {
                view.setOnLongClickListener(mOnLongClickListener);
            }
        }
 
        @Override
        public void onChildViewDetachedFromWindow(View view) {
 
        }
    };
 
    private ItemClickSupport(RecyclerView recyclerView) {
        mRecyclerView = recyclerView;
        mRecyclerView.setTag(R.id.item_click_support, this);
        mRecyclerView.addOnChildAttachStateChangeListener(mAttachListener);
    }
 
    public static ItemClickSupport addTo(RecyclerView view) {
        ItemClickSupport support = (ItemClickSupport) view.getTag(R.id.item_click_support);
        if (support == null) {
            support = new ItemClickSupport(view);
        }
        return support;
    }
 
    public static ItemClickSupport removeFrom(RecyclerView view) {
        ItemClickSupport support = (ItemClickSupport) view.getTag(R.id.item_click_support);
        if (support != null) {
            support.detach(view);
        }
        return support;
    }
 
    public ItemClickSupport setOnItemClickListener(OnItemClickListener listener) {
        mOnItemClickListener = listener;
        return this;
    }
 
    public ItemClickSupport setOnItemLongClickListener(OnItemLongClickListener listener) {
        mOnItemLongClickListener = listener;
        return this;
    }
 
    private void detach(RecyclerView view) {
        view.removeOnChildAttachStateChangeListener(mAttachListener);
        view.setTag(R.id.item_click_support, null);
    }
 
    public interface OnItemClickListener {
 
        void onItemClicked(RecyclerView recyclerView, int position, View v);
    }
 
    public interface OnItemLongClickListener {
 
        boolean onItemLongClicked(RecyclerView recyclerView, int position, View v);
    }
}
 
ItemClickSupport.addTo(mRecyclerView).setOnItemClickListener(
  new ItemClickSupport.OnItemClickListener() {
      @Override
      public void onItemClicked(RecyclerView recyclerView, int position, View v) {
          // do it
      }
  }
);

Прикрепление Click Handlers используя Listeners

В некоторых случаях, вы хотите настроить обработчиков щелчка для видов в RecyclerView но определить логику щелчка внутри содержащей активности или фрагмента (т.е. поднять событие от адаптера). Для достижения этой цели, создать пользовательский слушатель внутри адаптера, а затем передать событие вверх реализации интерфейса, определенного внутри родителя:

public class ContactsAdapter extends RecyclerView.Adapter<ContactsAdapter.ViewHolder> {
    // ...

    /***** Creating OnItemClickListener *****/
    
    // Define listener member variable    
    private OnItemClickListener listener;
    // Define the listener interface
    public interface OnItemClickListener {
        void onItemClick(View itemView, int position);
    }
    // Define the method that allows the parent activity or fragment to define the listener
    public void setOnItemClickListener(OnItemClickListener listener) {
        this.listener = listener;
    }

    public static class ViewHolder extends RecyclerView.ViewHolder {
        public TextView tvName;
        public TextView tvHometown;

        public ViewHolder(final View itemView) {
            super(itemView);
            this.tvName = (TextView) itemView.findViewById(R.id.tvName);
            this.tvHometown = (TextView) itemView.findViewById(R.id.tvHometown);
            // Setup the click listener
            itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    // Triggers click upwards to the adapter on click
                    if (listener != null)
                        listener.onItemClick(itemView, getLayoutPosition());
                }
            });
        }
    }
    
    // ...
}

Тогда мы можем прикрепить обработчик щелчка к адаптеру:

// In the activity or fragment
ContactsAdapter adapter = ...;
adapter.setOnItemClickListener(new ContactsAdapter.OnItemClickListener() {
    @Override
    public void onItemClick(View view, int position) {
        String name = users.get(position).name;
        Toast.makeText(UserListActivity.this, name + " was clicked!", Toast.LENGTH_SHORT).show();
    }
});

Обработка Scrolls с CoordinatorLayout

CoordinatorLayout расширяет возможности для выполнения многих эффектов прокрутки дизайна материалов Google. В настоящее время существует несколько способов, предусмотренные в этом фреймворке, которые позволяют ему работать без необходимости писать свой собственный пользовательский код анимации. Эти эффекты включают в себя:
Перемещение кнопки действие вверх и вниз, чтобы освободить место для Snackbar.
Расширение или сжатие панели инструментов или пространства заголовка, чтобы освободить место для основного содержания.
Контроль, какой вид должны развернуть или свернуть и с какой скоростью, включая анимацию parallax scrolling.
 
Floating Action Buttons и Snackbars
 
CoordinatorLayout может быть использован для создания плавающих эффектов с помощью layout_anchor и layout_gravity атрибутов. 
 
Когда Snackbar отображается, она обычно появляется в нижней части видимого экрана. Чтобы обеспечить пространство для этого, кнопка действия должны быть перемещена для предоставления места.
 
Пока CoordinatorLayout используется в качестве основного макета, этот эффект анимации будет происходить автоматически. Плавающая кнопка действия имеет поведение по умолчанию, которое определяет добавление вида Snackbar и оживляет кнопку выше высоты Snackbar.
<android.support.design.widget.CoordinatorLayout
        android:id="@+id/main_content"
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

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

   <android.support.design.widget.FloatingActionButton
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|right"
        android:layout_margin="16dp"
        android:src="@mipmap/ic_launcher"
        app:layout_anchor="@id/rvToDoList"
        app:layout_anchorGravity="bottom|right|end"/>
 </android.support.design.widget.CoordinatorLayout>

 

Разворачивание и сворачивание панели инструментов

Первый шаг, нужно убедиться, что вы не используете устаревший ActionBar. Также убедитесь, что CoordinatorLayout является основным макетом контейнера.

<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/main_content"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true">

      <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />

</android.support.design.widget.CoordinatorLayout>
Ответ на события прокрутки
 
Далее, мы должны сделать, чтобы Toolbar реагировала на события прокрутки, используя макет контейнера под названием AppBarLayout:
<android.support.design.widget.AppBarLayout
        android:id="@+id/appbar"
        android:layout_width="match_parent"
        android:layout_height="@dimen/detail_backdrop_height"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
        android:fitsSystemWindows="true">

  <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />

 </android.support.design.widget.AppBarLayout>

AppBarLayout должен быть первым дочерним элементом, вложенным в CoordinatorLayout.

Далее, мы должны определить связь между AppBarLayout и видом, который будет прокручиваться. Добавьте app:layout_behavior к RecyclerView или любому другому виду, способному содержать прокрутку, такому как NestedScrollView.

Библиотека поддержки содержит специальный строковый ресурс @string/appbar_scrolling_view_behavior, который отображается на AppBarLayout.ScrollingViewBehavior, который используется, чтобы уведомить AppBarLayout, когда события прокрутки происходят на данном виде. Поведение должно быть установлено на том виде, который вызывает событие.

<android.support.v7.widget.RecyclerView
        android:id="@+id/rvToDoList"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">
Когда CoordinatorLayout замечает этот атрибут, объявленный в RecyclerView, он будет искать через другие виды, содержащиеся в нем, все связанные представления, связанные с поведением. В данном конкретном случае, AppBarLayout.ScrollingViewBehavior описывает зависимость между RecyclerView и AppBarLayout. Любые события прокрутки для RecyclerView должны вызывать изменения в макете AppBarLayout или любых видах, содержащихся в нем.
 
События прокрутки в RecyclerView запускают изменения внутри видах, объявленных в AppBarLayout, используя app:layout_scrollFlags:
<android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:fitsSystemWindows="true"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

            <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                app:layout_scrollFlags="scroll|enterAlways"/>

 </android.support.design.widget.AppBarLayout>
Флаг scroll используется в атрибуте app:layout_scrollFlags и должен быть включен для того, чтобы вид прокручивался с экрана. В противном случае, он будет оставаться прижатым к верхней части. Другие флаги, которые могут быть использованы:
 
enterAlways: вид станет видимым при прокрутке.
 
enterAlwaysCollapsed: предполагая, что вы объявили MinHeight и enterAlways, ваш вид будет появляться только на его минимальную высоту и расширяться до полной высоты, когда прокрутка вида достигает вершины.
 
exitUntilCollapsed: предполагая, что вы объявили MinHeight, вид исчезнет, как только минимальная высота будет достигнута.
 
Создание Collapsing эффекта
 
Если мы хотим создать эффект Collapsing для панели инструментов, мы должны обернуть панель инструментов внутри CollapsingToolbarLayout:
<android.support.design.widget.CollapsingToolbarLayout
            android:id="@+id/collapsing_toolbar"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:fitsSystemWindows="true"
            app:contentScrim="?attr/colorPrimary"
            app:expandedTitleMarginEnd="64dp"
            app:expandedTitleMarginStart="48dp"
            app:layout_scrollFlags="scroll|exitUntilCollapsed">
            
            <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                app:layout_scrollFlags="scroll|enterAlways"></android.support.v7.widget.Toolbar>
        </android.support.design.widget.CollapsingToolbarLayout>

Обычно мы устанавливаем название панели инструментов. Теперь мы должны установить заголовок на CollapsingToolBarLayout вместо панели инструментов.

CollapsingToolbarLayout collapsingToolbar =
              (CollapsingToolbarLayout) findViewById(R.id.collapsing_toolbar);
      collapsingToolbar.setTitle("Title");
Создание анимации Parallax
 
CollapsingToolbarLayout также позволяет делать более продвинутые анимации, такие как использование ImageView, который исчезает, когда вид коллапсирует. Заголовок может также измениться в высоту когда пользователь прокручивает.
 
Чтобы создать этот эффект, мы добавляем ImageView и объявляем app:layout_collapseMode="parallax" атрибут.
<android.support.design.widget.CollapsingToolbarLayout
          android:id="@+id/collapsing_toolbar"
          android:layout_width="match_parent"
          android:layout_height="match_parent"
          android:fitsSystemWindows="true"
          app:contentScrim="?attr/colorPrimary"
          app:expandedTitleMarginEnd="64dp"
          app:expandedTitleMarginStart="48dp"
          app:layout_scrollFlags="scroll|exitUntilCollapsed">

          <android.support.v7.widget.Toolbar
              android:id="@+id/toolbar"
              android:layout_width="match_parent"
              android:layout_height="?attr/actionBarSize"
              app:layout_scrollFlags="scroll|enterAlways"></android.support.v7.widget.Toolbar>
          <ImageView
              android:src="@drawable/cheese_1"
              app:layout_scrollFlags="scroll|enterAlways|enterAlwaysCollapsed"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:scaleType="centerCrop"
              app:layout_collapseMode="parallax"
              android:minHeight="100dp"/>

      </android.support.design.widget.CollapsingToolbarLayout>
Пользовательские поведения
 
CoordinatorLayout работает путем поиска любого дочернего вида, который имеет определенное CoordinatorLayout Behavior либо статически в XML с app:layout_behavior тегом или программно с классом вида с аннотацией декоратора @DefaultBehavior. Когда происходит событие прокрутки, CoordinatorLayout пытается вызвать другие дочерние представления, которые объявлены в качестве зависимостей.
 
Чтобы определить свое собственное поведение CoordinatorLayout, методы layoutDependsOn() и onDependentViewChanged() должны быть реализованы. Например, AppBarLayout.Behavior имеет эти два ключевых метода. Такое поведение используется, чтобы вызвать изменения на AppBarLayout, когда происходит событие прокрутки.
public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {
          return dependency instanceof AppBarLayout;
      }

 public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {
          // check the behavior triggered
          android.support.design.widget.CoordinatorLayout.Behavior behavior = ((android.support.design.widget.CoordinatorLayout.LayoutParams)dependency.getLayoutParams()).getBehavior();
          if(behavior instanceof AppBarLayout.Behavior) {
          // do stuff here
          }
 }       
Snackbars обеспечивают легкий отзыв операции. Они показывают короткое сообщение в нижней части экрана на телефоне и в нижней левой части на больших устройствах. Snackbars появляются над всеми другими элементами на экране и только одно сообщение может одновременно отображаться.
 
Они автоматически исчезает после тайм-аута или после взаимодействия с пользователем в другом месте на экране, особенно после взаимодействий, которые вызывают новую поверхность активности. Snackbars можно убрать с экрана.
 
Snackbars могут содержать действие, заданное с помощью setAction(CharSequence, android.view.View.OnClickListener).
 
Чтобы получать уведомления, когда snackbar был показан или убран, вы можете обеспечить Snackbar.Callback через setCallback(Callback).
 
FabButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Snackbar.make(v,"This is sample snack bar text",Snackbar.LENGTH_SHORT).show(); } });
 
<android.support.design.widget.CoordinatorLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:layout_centerHorizontal="true" android:id="@+id/snackbarlocation">
 
</android.support.design.widget.CoordinatorLayout>
 
CoordinatorLayout Clayout = (CoordinatorLayout)findViewById(R.id.snackbarlocation); FabButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Snackbar.make(Clayout, "This snack bar located at top", Snackbar.LENGTH_SHORT).show(); } });
 
Snackbar.make(Clayout, "This snack bar located at top", Snackbar.LENGTH_LONG). setAction("Retry",snackbarClickListener).show();
 
View.OnClickListener snackbarClickListener = new View.OnClickListener() { @Override public void onClick(View v) { } };
 

<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity">

<android.support.design.widget.FloatingActionButton android:id="@+id/add_fab_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/abc_ic_ab_back_mtrl_am_alpha" android:layout_gravity="end|bottom" app:borderWidth="0dp"/>

<android.support.design.widget.FloatingActionButton android:id="@+id/add_fab_button1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/abc_ic_ab_back_mtrl_am_alpha" android:layout_gravity="bottom|left" app:borderWidth="0dp"/>

</android.support.design.widget.CoordinatorLayout>