- ItemTouchHelper
- Class Overview
- Item touch helper android
- Пролог
- Первые потери и свет в конце туннеля
- Разбор полётов
- Drag и Swipe в RecyclerView. Часть 1: ItemTouchHelper
- ItemTouchHelper
- Настройка
- Использование ItemTouchHelper и ItemTouchHelper.Callback
- Заключение
- Исходный код
- Drag и Swipe в RecyclerView. Часть 1: ItemTouchHelper
- ItemTouchHelper
- Настройка
- Использование ItemTouchHelper и ItemTouchHelper.Callback
- Заключение
- Исходный код
ItemTouchHelper
java.lang.Object | ||
↳ | android.support.v7.widget.RecyclerView.ItemDecoration | |
↳ | android.support.v7.widget.helper.ItemTouchHelper |
Class Overview
This is a utility class to add swipe to dismiss and drag & drop support to RecyclerView.
It works with a RecyclerView and a Callback class, which configures what type of interactions are enabled and also receives events when user performs these actions.
Depending on which functionality you support, you should override onMove(RecyclerView, ViewHolder, ViewHolder) and / or onSwiped(ViewHolder, int) .
This class is designed to work with any LayoutManager but for certain situations, it can be optimized for your custom LayoutManager by extending methods in the ItemTouchHelper.Callback class or implementing ItemTouchHelper.ViewDropHandler interface in your LayoutManager.
By default, ItemTouchHelper moves the items’ translateX/Y properties to reposition them. On platforms older than Honeycomb, ItemTouchHelper uses canvas translations and View’s visibility property to move items in response to touch events. You can customize these behaviors by overriding onChildDraw(Canvas, RecyclerView, ViewHolder, float, float, int, boolean) or onChildDrawOver(Canvas, RecyclerView, ViewHolder, float, float, int, boolean) .
Most of the time, you only need to override onChildDraw but due to limitations of platform prior to Honeycomb, you may need to implement onChildDrawOver as well.
Источник
Item touch helper android
Дисклеймер: статья наполнена как технической информацией, так и простой болью из жизни Andoid-разработчика. Если вам нужно коротко и по существу, то смело начинайте читать с раздела “Разбор полётов”. Если же вы хотите всем сердцем посопереживать и поддержать автора, то прочтите её полностью.
Пролог
Хотя было весьма холодно, зимний день обещал быть не из плохих. Придя на работу, я, как всегда, заварил чай, и вот, усевшись попивать тёплый чаёк с печеньками, я был прерван тимлидом, который собирался показать мне обновленный дизайн проекта. Тут-то мне и стоило заподозрить неладное.
На меня положили задачу переписывания адаптера для главного экрана приложения. И всё было бы хорошо, если бы он не был таким комплексным. Скриншоты самого дизайна я показать вам не могу с ясных причин, но могу вкратце описать проблематику: некоторые данные могут группироваться в группах( Xzibit.jpeg ). Но если большее множество разработчиков знает, как это можно реализовать, то следущая задача была на порядок сложнее.
Большинство знает о паттерне swipe-to-dismiss. Его можно встретить в двух из каждых трёх приложений(прим. — не игр), устрановленных на вашем планшете или смартфоне. И так, вы берете итем в адаптере, “тащите” его в правую или левую сторону, и он тащится за вашим пальцем. Исходя из направления, в котором вы потащили итем, вызывается соответствующий обработчик: удаляете, архивируете, отмечаете выполненным, вызываете диалог с действиями, и т.д.
В моём же задании при свайпе вправо событие отмечается выполненным, но вот действия при свайпе влево куда сложнее. Для них нужно знать величину смещения итема от левого края, причём сам итем не двигается, а надвигается “плашка” поверх итема.
Первые потери и свет в конце туннеля
Android-разработчики — существа ленивые, впрочем, как и все разработчики. Они не очень-то и любят писать сложное поведение UI вручную, когда можно найти подобную либу на Android Arsenal. Только тут есть одна проблема: я работаю c RecyclerView почти с самого его анонса, и вам советую на него переходить, если вы ещё каким-то чудом не начали его использовать.
Для RecyclerView , ИМХО, существует всё ещё мало хороших стабильных библиотек, созданных сообществом. Лично моя некогда любимая библиотека, Advanced RecyclerView, к чертям поменяла своё API, и мне пришлось потратить пару часов своей жизни просто на миграцию на более новую версию. Таковы причуды открытого сообщества разработчиков, ага.
Пересмотрев “обилие” подходящих решений, я убедился, что придется чуть ли не самому вешать на каждый итем свой OnTouchListener с нужными мне обработчиками. Но оставалась последняя надежда.
Загуглив очередной раз, я наткнулся на некий ItemTouchHelper , который умел всё то, что я искал. И самое главное, что сам класс есть в библиотеке com.android.support:recyclerview-v7 , которую наша любимая Android Studio по-умолчанию добавляет в блок зависимостей build.gradle , или же вы сами добавляете ее при использовании RecyclerView .
Разбор полётов
Для начала стоит заметить, что сам ItemTouchHelper практически никак не связан c реализацией адаптера. Он скорее связан с вашей реализацией ViewHolder -а.
Для того, чтобы воспользоваться всеми достоинствами хелпера, нам нужно создать собственный ItemTouchHelper.Callback . Это интерфейс, позволяющий приложению следить за тем, как пользователь “свайпает” или переставляет итемы между собой. Перемещение я рассматривать не буду, хотя его реализация весьма проста.
Рассмотрим нужные нам методы “коллбека”:
Ну и ещё парочку тех, которые нам нужно переопределить:
1 . getMovementFlags — позволяет вам задавать флаги движения для каждого итема в RecyclerView , который представленный его ViewHolder -ом.
Зададим возможность свайпать только если это обычный итем, а не заголовок в группе.
Наш адаптер же выглядит примерно так:
Заранее не забудем, что нужно “включить” возможность свайпа итемов и “отключить” возможность их перемещения между собой:
Метод onMove нам не понадобится в силу неиспользования возможности перемещать итемы между собой:
2 . onSwiped() — метод, который вызывается после того, как итем был конечно перемещён вправо или влево. Тут можно запросто узнать направление свайпа и вызвать нужный нам метод:
И так, о параметрах:
- Canvas c — канвасы для отрисовки.
- float dX — смещение итема относительно оси X в пикселах.
- float dY — смещение итема относительно оси Y в пикселах.
- int actionState — представлеяет какое действие сейчас происходит. Может принимать значения ACTION_STATE_SWIPE , ACTION_STATE_DRAG и ACTION_STATE_IDLE .
- boolean isCurrentlyActive — true , если итем двигает человек, false , если итем двигается программно.
В конце концов, после создания вашего коллбека, вам нужно “навесить” сделанный вами обработчик на вашу RecyclerView . Делается это очень просто:
Ну вот и всё, ваш свайп готов, можно жать на “Run” и идти пить чай.
Статью меня попросили написать в нашем ламповом Android-диалоге в Telegram. Заходите к нам, там уютно.
Если же у вас есть вопросы, то вы можете оставлять их здесь в комментариях, в нашем Android-чате в Telegram, или писать мне в личку в VK.
Ну а если вы хотите поделиться своим опытом у нас в блоге, то смело обращайтесь ко мне, или к другим администраторам “ІТ КПІ”. Помните, у вас всегда есть такая возможность!
Источник
Drag и Swipe в RecyclerView. Часть 1: ItemTouchHelper
Существует множество обучающих материалов, библиотек и примеров реализации drag & drop и swipe-to-dismiss в Android c использованием RecyclerView. В большинстве из них по-прежнему используются устаревший View.OnDragListener и подход SwipeToDismiss, разработанный Романом Нуриком. Хотя уже доступны новые и более эффективные методы. Совсем немногие используют новейшие API, зачастую полагаясь на GestureDetectors и onInterceptTouchEvent или же на другие более сложные имплементации. На самом деле существует очень простой способ добавить эти функции в RecyclerView . Для этого требуется всего лишь один класс, который к тому же является частью Android Support Library.
ItemTouchHelper
ItemTouchHelper — это мощная утилита, которая позаботится обо всём, что необходимо сделать, чтобы добавить функции drag & drop и swipe-to-dismiss в RecyclerView . Эта утилита является подклассом RecyclerView.ItemDecoration, благодаря чему её легко добавить практически к любому существующему LayoutManager и адаптеру. Она также работает с анимацией элементов и предоставляет возможность перетаскивать элементы одного типа на другое место в списке и многое другое. В этой статье я продемонстрирую простую реализацию ItemTouchHelper . Позже, в рамках этой серии статей, мы расширим рамки и рассмотрим остальные возможности.
Примечание. Хотите сразу увидеть результат? Загляните на Github: Android-ItemTouchHelper-Demo. Первый коммит относится к этой статье. Демо .apk -файл можно скачать здесь.
Настройка
Сперва нам нужно настроить RecyclerView . Если вы ещё этого не сделали, добавьте зависимость RecyclerView в свой файл build.gradle .
ItemTouchHelper будет работать практически с любыми RecyclerView.Adapter и LayoutManager , но эта статья базируется на примерах, использующих эти файлы.
Использование ItemTouchHelper и ItemTouchHelper.Callback
Чтобы использовать ItemTouchHelper , вам необходимо создать ItemTouchHelper.Callback. Это интерфейс, который позволяет отслеживать действия перемещения (англ. move) и смахивания (англ. swipe). Кроме того, здесь вы можете контролировать состояние выделенного view -компонента и переопределять анимацию по умолчанию. Существует вспомогательный класс, который вы можете использовать, если хотите использовать базовую имплементацию, — SimpleCallback. Но для того, чтобы понять, как это работает на практике, сделаем всё самостоятельно.
Основные функции интерфейса, которые мы должны переопределить, чтобы включить базовый функционал drag & drop и swipe-to-dismiss:
Мы также будем использовать несколько вспомогательных методов:
Рассмотрим их поочередно.
ItemTouchHelper позволяет легко определить направление события. Вам нужно переопределить метод getMovementFlags() , чтобы указать, какие направления для перетаскивания будут поддерживаться. Для создания возвращаемых флагов используйте вспомогательный метод ItemTouchHelper.makeMovementFlags(int, int) . В этом примере мы разрешаем перетаскивание и смахивание в обоих направлениях.
ItemTouchHelper можно использовать только для перетаскивания без функционала смахивания (или наоборот), поэтому вы должны точно указать, какие функции должны поддерживаться. Метод isLongPressDragEnabled() должен возвращать значение true , чтобы поддерживалось перетаскивание после длительного нажатия на элемент RecyclerView . В качестве альтернативы можно вызвать метод ItemTouchHelper.startDrag(RecyclerView.ViewHolder) , чтобы начать перетаскивание вручную. Рассмотрим этот вариант позже.
Чтобы разрешить смахивание после касания где угодно в рамках view -компонента, просто верните значение true из метода isItemViewSwipeEnabled() . В качестве альтернативы можно вызвать метод ItemTouchHelper.startSwipe(RecyclerView.ViewHolder) , чтобы начать смахивание вручную.
Следующие два метода, onMove() и onSwiped() , необходимы для того, чтобы уведомить об обновлении данных. Итак, сначала мы создадим интерфейс, который позволит передать эти события по цепочке вызовов.
Самый простой способ сделать это — сделать так, чтобы RecyclerListAdapter имплементировал слушателя.
Очень важно вызвать методы notifyItemRemoved() и notifyItemMoved() , чтобы адаптер увидел изменения. Также нужно отметить, что мы меняем позицию элемента каждый раз, когда view -компонент смещается на новый индекс, а не в самом конце перемещения (событие «drop»).
Теперь мы можем вернуться к созданию SimpleItemTouchHelperCallback , поскольку нам всё ещё необходимо переопределить методы onMove() и onSwiped() . Сначала добавьте конструктор и поле для адаптера:
Затем переопределите оставшиеся события и сообщите об этом адаптеру:
В результате класс Callback должен выглядеть примерно так:
Когда Callback готов, мы можем создать ItemTouchHelper и вызвать метод attachToRecyclerView(RecyclerView) (например, в MainFragment.java):
После запуска должно получиться приблизительно следующее:
Заключение
Это максимально упрощённая реализация ItemTouchHelper . Тем не менее, вы можете заметить, что вам не обязательно использовать стороннюю библиотеку для реализации стандартных действий drag & drop и swipe-to-dismiss в RecyclerView . В следующей части мы уделим больше внимания внешнему виду элементов в момент перетаскивания или смахивания.
Исходный код
Я создал проект на GitHub для демонстрации того, о чём рассказывается в этой серии статей: Android-ItemTouchHelper-Demo. Первый коммит в основном относится к этой части и немного ко второй.
Источник
Drag и Swipe в RecyclerView. Часть 1: ItemTouchHelper
Существует множество обучающих материалов, библиотек и примеров реализации drag & drop и swipe-to-dismiss в Android c использованием RecyclerView. В большинстве из них по-прежнему используются устаревший View.OnDragListener и подход SwipeToDismiss, разработанный Романом Нуриком. Хотя уже доступны новые и более эффективные методы. Совсем немногие используют новейшие API, зачастую полагаясь на GestureDetectors и onInterceptTouchEvent или же на другие более сложные имплементации. На самом деле существует очень простой способ добавить эти функции в RecyclerView . Для этого требуется всего лишь один класс, который к тому же является частью Android Support Library.
ItemTouchHelper
ItemTouchHelper — это мощная утилита, которая позаботится обо всём, что необходимо сделать, чтобы добавить функции drag & drop и swipe-to-dismiss в RecyclerView . Эта утилита является подклассом RecyclerView.ItemDecoration, благодаря чему её легко добавить практически к любому существующему LayoutManager и адаптеру. Она также работает с анимацией элементов и предоставляет возможность перетаскивать элементы одного типа на другое место в списке и многое другое. В этой статье я продемонстрирую простую реализацию ItemTouchHelper . Позже, в рамках этой серии статей, мы расширим рамки и рассмотрим остальные возможности.
Примечание. Хотите сразу увидеть результат? Загляните на Github: Android-ItemTouchHelper-Demo. Первый коммит относится к этой статье. Демо .apk -файл можно скачать здесь.
Настройка
Сперва нам нужно настроить RecyclerView . Если вы ещё этого не сделали, добавьте зависимость RecyclerView в свой файл build.gradle .
ItemTouchHelper будет работать практически с любыми RecyclerView.Adapter и LayoutManager , но эта статья базируется на примерах, использующих эти файлы.
Использование ItemTouchHelper и ItemTouchHelper.Callback
Чтобы использовать ItemTouchHelper , вам необходимо создать ItemTouchHelper.Callback. Это интерфейс, который позволяет отслеживать действия перемещения (англ. move) и смахивания (англ. swipe). Кроме того, здесь вы можете контролировать состояние выделенного view -компонента и переопределять анимацию по умолчанию. Существует вспомогательный класс, который вы можете использовать, если хотите использовать базовую имплементацию, — SimpleCallback. Но для того, чтобы понять, как это работает на практике, сделаем всё самостоятельно.
Основные функции интерфейса, которые мы должны переопределить, чтобы включить базовый функционал drag & drop и swipe-to-dismiss:
Мы также будем использовать несколько вспомогательных методов:
Рассмотрим их поочередно.
ItemTouchHelper позволяет легко определить направление события. Вам нужно переопределить метод getMovementFlags() , чтобы указать, какие направления для перетаскивания будут поддерживаться. Для создания возвращаемых флагов используйте вспомогательный метод ItemTouchHelper.makeMovementFlags(int, int) . В этом примере мы разрешаем перетаскивание и смахивание в обоих направлениях.
ItemTouchHelper можно использовать только для перетаскивания без функционала смахивания (или наоборот), поэтому вы должны точно указать, какие функции должны поддерживаться. Метод isLongPressDragEnabled() должен возвращать значение true , чтобы поддерживалось перетаскивание после длительного нажатия на элемент RecyclerView . В качестве альтернативы можно вызвать метод ItemTouchHelper.startDrag(RecyclerView.ViewHolder) , чтобы начать перетаскивание вручную. Рассмотрим этот вариант позже.
Чтобы разрешить смахивание после касания где угодно в рамках view -компонента, просто верните значение true из метода isItemViewSwipeEnabled() . В качестве альтернативы можно вызвать метод ItemTouchHelper.startSwipe(RecyclerView.ViewHolder) , чтобы начать смахивание вручную.
Следующие два метода, onMove() и onSwiped() , необходимы для того, чтобы уведомить об обновлении данных. Итак, сначала мы создадим интерфейс, который позволит передать эти события по цепочке вызовов.
Самый простой способ сделать это — сделать так, чтобы RecyclerListAdapter имплементировал слушателя.
Очень важно вызвать методы notifyItemRemoved() и notifyItemMoved() , чтобы адаптер увидел изменения. Также нужно отметить, что мы меняем позицию элемента каждый раз, когда view -компонент смещается на новый индекс, а не в самом конце перемещения (событие «drop»).
Теперь мы можем вернуться к созданию SimpleItemTouchHelperCallback , поскольку нам всё ещё необходимо переопределить методы onMove() и onSwiped() . Сначала добавьте конструктор и поле для адаптера:
Затем переопределите оставшиеся события и сообщите об этом адаптеру:
В результате класс Callback должен выглядеть примерно так:
Когда Callback готов, мы можем создать ItemTouchHelper и вызвать метод attachToRecyclerView(RecyclerView) (например, в MainFragment.java):
После запуска должно получиться приблизительно следующее:
Заключение
Это максимально упрощённая реализация ItemTouchHelper . Тем не менее, вы можете заметить, что вам не обязательно использовать стороннюю библиотеку для реализации стандартных действий drag & drop и swipe-to-dismiss в RecyclerView . В следующей части мы уделим больше внимания внешнему виду элементов в момент перетаскивания или смахивания.
Исходный код
Я создал проект на GitHub для демонстрации того, о чём рассказывается в этой серии статей: Android-ItemTouchHelper-Demo. Первый коммит в основном относится к этой части и немного ко второй.
Источник