В следующих разделах объясняются несколько ключевых концепций процесса перетаскивания.
Процесс перетаскивания
В процессе перетаскивания есть четыре этапа или состояния: начало, продолжение, удаление и завершение.
- Начал
В ответ на жест перетаскивания пользователя ваше приложение вызывает
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_DRAG_ENDED
чтобы указать, что операция перетаскивания завершена. Это делается независимо от того, где пользователь отпускает тень. Событие отправляется каждому прослушивателю, зарегистрированному для получения событий перетаскивания, даже если прослушиватель также получает событиеACTION_DROP
.
Каждый из этих шагов более подробно описан в разделе « Операция перетаскивания» .
Перетаскивание событий
Система отправляет событие перетаскивания в форме объекта DragEvent
, который содержит тип действия, описывающий, что происходит в процессе перетаскивания. В зависимости от типа действия объект может содержать и другие данные.
Прослушиватели событий перетаскивания получают объект DragEvent
. Чтобы получить тип действия, слушатели вызывают DragEvent.getAction()
. Существует шесть возможных значений, определенных константами в классе DragEvent
, которые описаны в таблице 1:
Тип действия | Значение |
---|---|
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 не означает, что удаление удалось. Слушатель должен вызвать getResult() , как показано в таблице 2 , чтобы получить значение, возвращаемое в ответ на ACTION_DROP . Если событие ACTION_DROP не отправлено, getResult() возвращает false . |
Объект DragEvent
также содержит данные и метаданные, которые ваше приложение предоставляет системе при вызове startDragAndDrop()
. Некоторые данные действительны только для определенных типов действий, как показано в таблице 2. Дополнительные сведения о событиях и связанных с ними данных см. в разделе « Операция перетаскивания» .
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.DragShadowBuilder
или переопределять его методы. По умолчанию вы получаете тень, которая имеет тот же вид, что иView
, которое вы передаете в качестве аргумента, с центром под местом, где пользователь касается экрана.-
View.DragShadowBuilder()
Если вы используете этот конструктор, объект
View
не будет доступен в объектеView.DragShadowBuilder
. Поле установлено в значение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
, используемой с событиями касания.