Ключевые идеи

Попробуйте способ создания композиций.
Jetpack Compose — это рекомендуемый набор инструментов для создания пользовательского интерфейса для Android. Узнайте, как использовать перетаскивание в Compose.

В следующих разделах объясняются несколько ключевых понятий, связанных с процессом перетаскивания (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_DROP ACTION_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 , обработчик которого не зарегистрирован, или если пользователь исчезает над чем-либо, что не является частью текущего макета.

Если сброс прошел успешно, обработчик возвращает логическое значение true . В противном случае он должен вернуть false .

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 используемых для обработки сенсорных событий.