В следующих разделах объясняются несколько ключевых понятий, связанных с процессом перетаскивания (drag-and-drop).
Процесс перетаскивания
Процесс перетаскивания состоит из четырех этапов или состояний: начало, продолжение, перетащено и завершение.
- Началось
В ответ на жест перетаскивания пользователя ваше приложение вызывает метод
startDragAndDrop()чтобы дать системе команду начать операцию перетаскивания. Аргументы метода содержат следующее:- Данные, которые нужно перетащить.
- Функция обратного вызова для рисования тени от перевоплощения
- Метаданные, описывающие перетаскиваемые данные.
- В ответ система обращается к вашему приложению для получения тени от перетаскивания. Затем система отображает тень от перетаскивания на устройстве.
- Далее система отправляет событие перетаскивания с типом действия
ACTION_DRAG_STARTEDобработчику событий перетаскивания всех объектовViewв текущем макете. Чтобы продолжить получать события перетаскивания, включая возможное событие сброса, обработчик событий перетаскивания должен возвращатьtrue. Это регистрирует обработчик в системе. Только зарегистрированные обработчики продолжают получать события перетаскивания. На этом этапе обработчики также могут изменить внешний вид целевого объектаView, чтобы показать, что представление может принимать событие сброса. - Если обработчик событий перетаскивания возвращает
false, он не получает событий перетаскивания для текущей операции до тех пор, пока система не отправит событие перетаскивания с типом действияACTION_DRAG_ENDED. Возвращаяfalse, обработчик сообщает системе, что он не заинтересован в операции перетаскивания и не хочет принимать перетаскиваемые данные.
- Продолжение
- Пользователь продолжает перетаскивание. Когда тень от перетаскиваемого объекта пересекает ограничивающий прямоугольник целевого объекта, система отправляет одно или несколько событий перетаскивания обработчику событий перетаскивания целевого объекта. Обработчик может изменить внешний
Viewцелевого объекта в ответ на событие. Например, если событие указывает на то, что тень от перетаскиваемого объекта входит в ограничивающий прямоугольник целевого объекта (тип действияACTION_DRAG_ENTERED), обработчик может отреагировать, выделивView. - Упавший
- Пользователь отпускает тень перетаскивания внутри ограничивающего прямоугольника целевого объекта. Система отправляет обработчику целевого объекта событие перетаскивания с типом действия
ACTION_DROP. Объект события перетаскивания содержит данные, которые передаются в систему при вызове методаstartDragAndDrop(), запускающего операцию. Ожидается, что обработчик вернет логическое значениеtrueесли он успешно обработает перетащенные данные. Этот шаг происходит только в том случае, если пользователь перетаскивает тень перетаскивания внутри ограничивающего прямоугольникаView, обработчик которого зарегистрирован для приема событий перетаскивания (целевого объекта). Если пользователь отпускает тень перетаскивания в любой другой ситуации, событие перетаскиванияACTION_DROPне отправляется. - Завершено
После того, как пользователь отпускает кнопку перетаскивания, и после того, как система отправляет
При необходимости система отправляет событие перетаскивания с типом действия
ACTION_DROP, чтобы указать на завершение операции перетаскивания. Это происходит независимо от того, где пользователь отпускает тень перетаскиваемого элемента. Событие отправляется каждому слушателюACTION_DROPACTION_DRAG_ENDED
Каждый из этих шагов более подробно описан в разделе «Операция перетаскивания» .
События перетаскивания
Система отправляет событие перетаскивания в виде объекта DragEvent , который содержит тип действия, описывающий происходящее в процессе перетаскивания. В зависимости от типа действия объект может также содержать другие данные.
Обработчики событий перетаскивания получают объект DragEvent . Чтобы получить тип действия, обработчики вызывают метод DragEvent.getAction() . Существует шесть возможных значений, определенных константами в классе DragEvent , которые описаны в таблице 1:
Таблица 1. Типы действий DragEvent
| Тип действия | Значение |
|---|---|
ACTION_DRAG_STARTED | Приложение вызывает метод startDragAndDrop() и получает тень от перетаскиваемого объекта. Если слушатель хочет продолжать получать события перетаскивания для этой операции, он должен вернуть системе логическое значение true . |
ACTION_DRAG_ENTERED | Тень от перетаскивания входит в ограничивающий прямоугольник View обработчика события перетаскивания. Это первый тип действия события, который получает обработчик, когда тень от перетаскивания входит в ограничивающий прямоугольник. |
ACTION_DRAG_LOCATION | После события ACTION_DRAG_ENTERED тень от перетаскиваемого объекта остается в пределах ограничивающего прямоугольника View обработчика события перетаскивания. |
ACTION_DRAG_EXITED | После события ACTION_DRAG_ENTERED и как минимум одного события ACTION_DRAG_LOCATION тень перетаскиваемого объекта перемещается за пределы ограничивающего прямоугольника View обработчика события перетаскивания. |
ACTION_DROP | Тень от перетаскивания исчезает над View , на которое направлен обработчик события перетаскивания. Этот тип действия отправляется обработчику события View только в том случае, если обработчик возвращает логическое значение true в ответ на событие перетаскивания ACTION_DRAG_STARTED . Этот тип действия не отправляется, если пользователь исчезает над View , обработчик которого не зарегистрирован, или если пользователь исчезает над чем-либо, что не является частью текущего макета. Если сброс прошел успешно, обработчик возвращает логическое значение |
ACTION_DRAG_ENDED | Система завершает операцию перетаскивания. Этому типу действия не обязательно предшествует событие ACTION_DROP . Если система отправляет событие ACTION_DROP , получение события ACTION_DRAG_ENDED не означает, что перетаскивание прошло успешно. Для получения значения, возвращаемого в ответ на ACTION_DROP , слушатель должен вызвать getResult() , как показано в таблице 2. Если событие ACTION_DROP не отправлено, метод getResult() возвращает false . |
Объект DragEvent также содержит данные и метаданные, которые ваше приложение предоставляет системе при вызове метода startDragAndDrop() . Некоторые данные действительны только для определенных типов действий, как показано в таблице 2. Для получения дополнительной информации о событиях и связанных с ними данных см. раздел «Операция перетаскивания» .
Таблица 2. Допустимые данные DragEvent по типу действия.
getAction()ценить | getClipDescription()ценить | getLocalState()ценить | getX()ценить | getY()ценить | getClipData()ценить | getResult()ценить |
|---|---|---|---|---|---|---|
ACTION_DRAG_STARTED | ✓ | ✓ | ||||
ACTION_DRAG_ENTERED | ✓ | ✓ | ||||
ACTION_DRAG_LOCATION | ✓ | ✓ | ✓ | ✓ | ||
ACTION_DRAG_EXITED | ✓ | ✓ | ||||
ACTION_DROP | ✓ | ✓ | ✓ | ✓ | ✓ | |
ACTION_DRAG_ENDED | ✓ | ✓ |
Методы DragEvent getAction() , describeContents() , writeToParcel() и toString() всегда возвращают корректные данные.
Если метод не содержит допустимых данных для определенного типа действия, он возвращает null или 0 в зависимости от типа результата.
Тень перетаскивания
Во время операции перетаскивания система отображает изображение, которое пользователь перетаскивает. При перемещении данных это изображение представляет собой перетаскиваемые данные. В других операциях изображение представляет собой какой-либо аспект операции перетаскивания.
Изображение называется тенью перетаскивания . Вы создаете ее с помощью методов, объявленных для объекта View.DragShadowBuilder . Вы передаете этот объект системе при начале операции перетаскивания с помощью startDragAndDrop() . В ответ на вызов startDragAndDrop() система вызывает методы обратного вызова, определенные в View.DragShadowBuilder , для получения тени перетаскивания.
Класс View.DragShadowBuilder имеет два конструктора:
-
View.DragShadowBuilder(View) Этот конструктор принимает любой из объектов
Viewвашего приложения. Конструктор сохраняет объектViewв объектеView.DragShadowBuilder, чтобы функции обратного вызова могли получить к нему доступ для создания тени перетаскивания. Объект View не обязательно должен быть темView, который пользователь выбирает для начала операции перетаскивания.При использовании этого конструктора вам не нужно расширять
View.DragShadowBuilderили переопределять его методы. По умолчанию вы получаете тень от перетаскивания, которая имеет тот же внешний вид, что иView, переданный в качестве аргумента, и центрируется под местом касания экрана пользователем.-
View.DragShadowBuilder() Если вы используете этот конструктор, в объекте
View.DragShadowBuilderне будет доступен объектView. Поле будет установлено вnull. Вам необходимо расширитьView.DragShadowBuilderи переопределить его методы, иначе тень от перетаскивания будет невидимой. Система не выдаст ошибку.
Класс View.DragShadowBuilder имеет два метода, которые совместно создают тень при перетаскивании:
-
onProvideShadowMetrics() Система вызывает этот метод сразу после вызова
startDragAndDrop(). Используйте этот метод для отправки системе размеров и точки касания тени перетаскиваемого объекта. Метод имеет два параметра:outShadowSize: объектPoint. Ширина тени при перетаскивании задаётся по осиx, а высота — по осиy.outShadowTouchPoint: объектPoint. Точка касания — это местоположение внутри тени перетаскивания, которое должно находиться под пальцем пользователя во время перетаскивания. Ее координата по оси X задается в координатахx, а по оси Y — вy.-
onDrawShadow() Сразу после вызова метода
onProvideShadowMetrics()система вызываетonDrawShadow()для создания тени при перетаскивании. Метод принимает один аргумент — объектCanvas, который система создает из параметров, предоставленных в методеonProvideShadowMetrics(). Метод рисует тень при перетаскивании на предоставленномCanvas.
Для повышения производительности уменьшите размер тени от перетаскивания. Для одного элемента можно использовать иконку. Для выбора нескольких элементов лучше использовать иконки, расположенные стопкой, а не целые изображения, разбросанные по экрану.
Обработчики событий перетаскивания и методы обратного вызова
View получает события перетаскивания либо через обработчик событий перетаскивания, реализующий интерфейс View.OnDragListener , либо через метод обратного вызова onDragEvent() представления. Когда система вызывает метод или обработчик, она передает аргумент DragEvent .
В большинстве случаев использование слушателя предпочтительнее использования метода обратного вызова. При проектировании пользовательских интерфейсов обычно не создаются подклассы классов View , но использование метода обратного вызова заставляет создавать подклассы для переопределения метода. В отличие от этого, можно реализовать один класс слушателя и использовать его с несколькими различными объектами View . Также его можно реализовать в виде анонимного встроенного класса или лямбда-выражения. Чтобы установить слушатель для объекта View , вызовите метод setOnDragListener() .
В качестве альтернативы вы можете изменить реализацию метода onDragEvent() по умолчанию, не переопределяя сам метод. Установите OnReceiveContentListener для представления; более подробную информацию см. в setOnReceiveContentListener() . После этого метод onDragEvent() по умолчанию будет выполнять следующие действия:
- Возвращает true в ответ на вызов функции
startDragAndDrop(). Вызывает метод
performReceiveContent()если данные, перетаскиваемые мышью, помещены в представление. Данные передаются в метод в виде объектаContentInfo. Метод вызываетOnReceiveContentListener.Возвращает true, если данные, полученные методом перетаскивания, помещены в представление и обрабатываются слушателем событий
OnReceiveContentListener.
Определите обработчик OnReceiveContentListener для обработки данных специально для вашего приложения. Для обеспечения обратной совместимости до уровня API 24 используйте версию OnReceiveContentListener из Jetpack.
Для объекта View можно использовать обработчик события перетаскивания и метод обратного вызова, в этом случае система сначала вызывает обработчик события. Система не вызывает метод обратного вызова, если обработчик события не возвращает false .
Сочетание метода onDragEvent() и View.OnDragListener аналогично сочетанию методов onTouchEvent() и View.OnTouchListener используемых для обработки сенсорных событий.
