I can write something like this in my Compose application:
var isDroppable by remember { mutableStateOf(false) }
val (textFieldValue, setTextFieldValue) = remember { mutableStateOf(TextFieldValue()) }
TextField(
value = textFieldValue,
onValueChange = setTextFieldValue,
modifier = Modifier
.offset(500.dp, 100.dp)
.requiredSize(200.dp, 200.dp)
.border(4.dp, if (isDroppable) Color.Green else Color.Red)
.onExternalDrag(
onDragStart = { externalDragValue ->
isDroppable = externalDragValue.dragData is androidx.compose.ui.DragData.Text
},
onDragExit = {
isDroppable = false
},
onDrop = { externalDragValue ->
isDroppable = false
val dragData = externalDragValue.dragData
if (dragData is androidx.compose.ui.DragData.Text) {
setTextFieldValue(textFieldValue.copy(
text = textFieldValue.text.substring(0, textFieldValue.selection.start) +
dragData.readText() +
textFieldValue.text.substring(textFieldValue.selection.end),
selection = TextRange(textFieldValue.selection.end)
))
}
},
)
)
I can then open Notepad, type some text, and drag that text into the Compose app.
My question is: How to get the opposite?
If I select some text in the Compose application, I should be able to drag it back to Notepad, either moving or copying it depending on whether Ctrl is held down, same as text components in native applications.
This is for Compose Multiplatform 1.7.0-beta02 and tested on Windows.
Modifier.dragAndDropSource()
has been commonized for Desktop as well.
Use it to drag from your app to other components of your app or other applications:
val textToExport = "Hello from Compose Multiplatform app!"
val textMeasurer = rememberTextMeasurer()
Box(modifier = Modifier
.size(200.dp)
.background(Color.LightGray)
.dragAndDropSource(
drawDragDecoration = {
// These are drawn as a visual representation of the component being dragged
drawRect(
color = Color.Red,
topLeft = Offset(x = 0f, y = size.height / 4),
size = Size(size.width, size.height / 2)
)
val textLayoutResult = textMeasurer.measure(
text = AnnotatedString("I'm being dragged"),
layoutDirection = layoutDirection,
density = this
)
drawText(
textLayoutResult = textLayoutResult,
topLeft = Offset(
x = (size.width - textLayoutResult.size.width) / 2,
y = (size.height - textLayoutResult.size.height) / 2,
)
)
}
) {
detectDragGestures(
onDragStart = { offset ->
startTransfer(
DragAndDropTransferData(
transferable = DragAndDropTransferable(
// This is what you want to export/transfer/move/drop
StringSelection(textToExport)
),
supportedActions = listOf(
DragAndDropTransferAction.Copy,
DragAndDropTransferAction.Move,
DragAndDropTransferAction.Link,
),
dragDecorationOffset = offset,
onTransferCompleted = { action ->
when (action) {
DragAndDropTransferAction.Copy -> println("Copied")
DragAndDropTransferAction.Move -> println("Moved")
DragAndDropTransferAction.Link -> println("Linked")
null -> println("Transfer aborted")
}
}
)
)
},
onDrag = { _, _ -> },
)
}
) {
Text("Drag Me", Modifier.align(Alignment.Center))
}
The code was adopted from the example in this pull request.