Перетаскивание

Jetpack Compose поддерживает перетаскивание с помощью двух модификаторов:

  • dragAndDropSource – указывает, что в качестве начальной точки жеста перетаскивания используется компонуемый элемент.
  • dragAndDropTarget: указывает на компонент, который принимает перетаскиваемые данные.

Например, чтобы пользователи могли перетаскивать изображение в вашем приложении, создайте composable-функцию image и добавьте модификатор dragAndDropSource. Чтобы настроить целевую область, создайте ещё один компонент изображения и добавьте модификатор dragAndDropTarget.

Модификаторы можно применять к нескольким источникам перетаскивания и нескольким целевым объектам.

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

Как указать источник перетаскивания

Чтобы разрешить перетаскивание событий внутри компонента, добавьте модификатор dragAndDropSource. В качестве параметра передается функция. Внутри этой функции используйте DragAndDropTransferData, чтобы представить передаваемые данные. Данные могут представлять собой удаленный URI, форматированный текст в буфере обмена, локальный файл и т. д., но все они должны быть заключены в объект ClipData. Укажите обычный текст, например:

Modifier.dragAndDropSource { _ ->
    DragAndDropTransferData(
        ClipData.newPlainText(
            "image Url", url
        )
    )
}

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

Modifier.dragAndDropSource { _ ->
    DragAndDropTransferData(
        ClipData.newPlainText(
            "image Url", url
        ),
        flags = View.DRAG_FLAG_GLOBAL
    )
}

DragAndDropTransferData принимает флаги, поддерживаемые системой Android View. Полный список доступных флагов можно найти в списке констант View.

Получение данных о дропах

Назначьте модификатор dragAndDropTarget composable-функции, чтобы она могла получать события перетаскивания. У модификатора два параметра: первый действует как фильтр и указывает, какие данные может принимать модификатор, а второй передает данные в обратном вызове.

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

val callback = remember {
    object : DragAndDropTarget {
        override fun onDrop(event: DragAndDropEvent): Boolean {
            // Parse received data
            return true
        }
    }
}

Чтобы принимать данные от других приложений, используйте requestDragAndDropPermission, чтобы включить прием, и отпустите его, когда все будет готово:

val externalAppCallback = remember {
    object : DragAndDropTarget {
        override fun onDrop(event: DragAndDropEvent): Boolean {
            val permission =
                activity.requestDragAndDropPermissions(event.toAndroidDragEvent())
            // Parse received data
            permission?.release()
            return true
        }
    }
}

Важно помнить, что объект DragAndDropEvent, возвращаемый из обратного вызова Compose, отличается от объекта, ожидаемого методом requestDragAndDropPermission, поэтому перед передачей параметра в запрос разрешения необходимо вызвать для него функцию расширения toAndroidDragEvent().

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

Modifier.dragAndDropTarget(
    shouldStartDragAndDrop = { event ->
        event.mimeTypes().contains(ClipDescription.MIMETYPE_TEXT_PLAIN)
    }, target = callback // or externalAppCallback
)

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

Как обрабатывать события перетаскивания

Переопределите обратные вызовы в интерфейсе DragAndDropTarget, чтобы отслеживать начало и конец события перетаскивания, а также вход и выход компонента. Это позволит вам точно управлять интерфейсом и поведением приложения.

object : DragAndDropTarget {
    override fun onStarted(event: DragAndDropEvent) {
        // When the drag event starts
    }

    override fun onEntered(event: DragAndDropEvent) {
        // When the dragged object enters the target surface
    }

    override fun onEnded(event: DragAndDropEvent) {
        // When the drag event stops
    }

    override fun onExited(event: DragAndDropEvent) {
        // When the dragged object exits the target surface
    }

    override fun onDrop(event: DragAndDropEvent): Boolean = true
}

Дополнительные ресурсы

Практическая работа: Перетаскивание в Compose