Arrastrar y soltar

Jetpack Compose admite la función de arrastrar y soltar con dos modificadores:

  • dragAndDropSource: Especifica un elemento componible como punto de partida del gesto de arrastre
  • dragAndDropTarget: Especifica un elemento componible que acepta los datos soltados.

Los modificadores permiten que las apps compartan datos entre dos o más elementos componibles con ClipData, que es interoperable con implementaciones de View.

Cómo iniciar un evento de arrastre

Para habilitar los eventos de arrastre dentro de un componente, agrega el modificador dragAndDropSource, que toma una función de suspensión como parámetro. La función define la interacción del usuario que inicia la operación de arrastre. El modificador dragAndDropSource espera hasta que recibe un evento de entrada de puntero y, luego, ejecuta la expresión lambda pasada al controlador de eventos. Usa la función lambda para detectar una variedad de eventos de entrada, por ejemplo, presiones o presiones presionadas. Para obtener más información, consulta Entrada de puntero en Compose.

El evento de entrada del puntero suele ser una acción de mantener presionado, de la siguiente manera:

Modifier.dragAndDropSource {
    detectTapGestures(onLongPress = {
        // Transfer data here.
    })
}

Para iniciar una sesión de arrastrar y soltar, llama a la función startTransfer(). Dentro de este alcance, usa DragAndDropTransferData para representar los datos transferibles. Los datos pueden ser un URI remoto, datos de texto enriquecido en el portapapeles, un archivo local o mucho más, pero todos deben unirse a un objeto ClipData. Proporciona texto sin formato, por ejemplo, como se indica a continuación:

Modifier.dragAndDropSource {
    detectTapGestures(onLongPress = {
        startTransfer(
            DragAndDropTransferData(
                ClipData.newPlainText(
                    "image Url", url
                )
            )
        )
    })
}

Para permitir que la acción de arrastre cruce los bordes de la app, el constructor DragAndDropTransferData acepta un argumento flags. En el siguiente ejemplo, la constante DRAG_FLAG_GLOBAL especifica que los datos se pueden arrastrar de una app a otra:

Modifier.dragAndDropSource {
    detectTapGestures(onLongPress = {
        startTransfer(
            DragAndDropTransferData(
                ClipData.newPlainText(
                    "image Url", url
                ),
                flags = View.DRAG_FLAG_GLOBAL
            )
        )
    })
}

DragAndDropTransferData acepta marcas compatibles con el sistema Android View. Consulta la lista de constantes de View para ver una lista completa de las marcas disponibles.

Recibir datos de soltar

Asigna el modificador dragAndDropTarget a un elemento componible para permitir que reciba eventos de arrastrar y soltar. El modificador tiene dos parámetros: el primero actúa como un filtro y especifica el tipo de datos que el modificador puede aceptar, y el segundo entrega los datos en una devolución de llamada.

Ten en cuenta que se debe recordar la instancia de devolución de llamada. En el siguiente fragmento, se muestra cómo recordar la devolución de llamada:

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

En el siguiente fragmento, se muestra cómo controlar el texto sin formato descartado:

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

La función de devolución de llamada debe mostrar true si se consume el evento, o bien false si se rechaza el evento y no se propaga al componente superior.

Cómo controlar eventos de arrastrar y soltar

Anula las devoluciones de llamada en la interfaz DragAndDropTarget para observar cuándo un evento de arrastrar y soltar comienza, finaliza, ingresa a un componente o sale de él para tener un control preciso de la IU y el comportamiento de la app:

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
}

Recursos adicionales

Codelab: Arrastra y suelta en Compose