Arrastar e soltar

O Jetpack Compose oferece suporte para arrastar e soltar com dois modificadores:

  • dragAndDropSource: especifica um elemento combinável como o ponto de partida do gesto de arrastar.
  • dragAndDropTarget: especifica um elemento combinável que aceita os dados soltos.

Por exemplo, para permitir que os usuários arrastem uma imagem no app, crie um elemento combinável de imagem e adicione o modificador dragAndDropSource. Para configurar um destino de soltar, crie outro elemento de imagem combinável e adicione o modificador dragAndDropTarget.

Os modificadores podem ser aplicados a várias origens de arrastar e vários destinos de soltar.

Os modificadores permitem que os apps compartilhem dados entre dois ou mais elementos combináveis usando ClipData, que é interoperável com as implementações de View.

Especificar uma origem de arrastar

Para ativar eventos de arrastar dentro de um componente, adicione o modificador dragAndDropSource. Isso usa uma função como parâmetro. Dentro dessa função, use DragAndDropTransferData para representar os dados transferíveis. Os dados podem ser um URI remoto, dados de rich text na área de transferência, um arquivo local ou mais, mas todos precisam ser encapsulados em um objeto ClipData. Forneça texto simples, por exemplo, da seguinte maneira:

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

Para permitir que a ação de arrastar ultrapasse as bordas do app, o construtor DragAndDropTransferData aceita um argumento flags. No exemplo a seguir, a constante DRAG_FLAG_GLOBAL especifica que os dados podem ser arrastados de um app para outro:

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

DragAndDropTransferData aceita flags compatíveis com o sistema de visualização do Android. Consulte a lista de constantes de visualização para ver uma lista completa das flags disponíveis.

Receber dados de soltura

Atribua o modificador dragAndDropTarget a um elemento combinável para que ele receba eventos de arrastar e soltar. O modificador tem dois parâmetros: o primeiro funciona como um filtro e especifica o tipo de dados que o modificador pode aceitar, e o segundo fornece os dados em um callback.

A instância de callback precisa ser lembrada. O snippet a seguir mostra como lembrar o callback:

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

Para aceitar dados de outros apps, use o requestDragAndDropPermission para ativar o recebimento e libere-o quando terminar:

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

É importante lembrar que o DragAndDropEvent retornado do callback do Compose é diferente do esperado pelo método requestDragAndDropPermission. Portanto, é necessário chamar a função de extensão toAndroidDragEvent() no parâmetro antes de transmiti-lo à solicitação de permissão.

O snippet a seguir demonstra como processar texto simples solto:

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

A função de callback precisa retornar true se o evento for consumido ou false se o evento for recusado e não se propagar para o componente pai.

Processar eventos de arrastar e soltar

Substitua os callbacks na interface DragAndDropTarget para observar quando um evento de arrastar e soltar começa, termina ou entra ou sai de um componente para um controle preciso da interface e do comportamento do 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
}

Outros recursos

Codelab: Arrastar e soltar no Compose