目前,拖放操作仅在 Compose 多平台的桌面端受到支持。在未来的版本中,这一支持将会扩展至 iOS 平台以及网页端。
你可以让你的 Compose 多平台应用能够接收用户从其他应用程序拖入其中的数据,或者允许用户将数据拖出你的应用。要实现这一点,可使用 “dragAndDropSource”(拖放源)和 “dragAndDropTarget”(拖放目标)修饰符来指定特定的可组合项作为拖放操作潜在的源或目标。
“dragAndDropSource”(拖放源)和 “dragAndDropTarget”(拖放目标)这两个修饰符均处于试验阶段,可能会发生变化,并且需要使用选择加入(opt-in)注解。
创建一个拖放源
要将一个可组合项设置为拖放源,需按以下步骤进行:
使用 detectDragGestures()
函数(例如,在 onDragStart
时)来选定拖放事件的触发条件。
调用 startTransfer()
函数,并通过 DragAndDropTransferData()
调用描述拖放会话。
通过 DragAndDropTransferable()
调用描述本应被拖放到目标位置的数据。
以下是一个 Box()
可组合项示例,它允许用户从中拖出一个字符串:
val exportedText = "Hello, drag and drop!"Box(Modifier.dragAndDropSource(// Creates a visual representation of the data being dragged// (white rectangle with the exportedText string centered on it).drawDragDecoration = {drawRect(color = Color.White,topLeft = Offset(x = 0f, y = size.height/4),size = Size(size.width, size.height/2))val textLayoutResult = textMeasurer.measure(text = AnnotatedString(exportedText),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(// Defines transferable data and supported transfer actions.// When an action is concluded, prints the result into// system output with onTransferCompleted().DragAndDropTransferData(transferable = DragAndDropTransferable(StringSelection(exportedText)),// List of actions supported by this drag source. A type of action// is passed to the drop target together with data.// The target can use this to reject an inappropriate drop operation// or to interpret user expectations.supportedActions = listOf(DragAndDropTransferAction.Copy,DragAndDropTransferAction.Move,DragAndDropTransferAction.Link,),dragDecorationOffset = offset,onTransferCompleted = { action ->println("Action at the source: $action")}))},onDrag = { _, _ -> },)}.size(200.dp).background(Color.LightGray)
) {Text("Drag Me", Modifier.align(Alignment.Center))
}
创建一个拖放目标
要将一个可组合项设置为拖放目标,需按以下步骤进行:
在 shouldStartDragAndDrop
lambda 表达式中描述可组合项成为拖放目标的条件。
创建(并记住)DragAndDropTarget
对象,该对象将包含你为拖放事件处理程序重写的内容。
编写必要的重写内容,例如,使用 onDrop
来解析接收到的数据,或者当可拖动对象进入可组合项时使用 onEntered
进行相应处理。
以下是一个准备好显示被拖入其中的文本的 Box()
可组合项示例:
var showTargetBorder by remember { mutableStateOf(false) }
var targetText by remember { mutableStateOf("Drop Here") }
val coroutineScope = rememberCoroutineScope()
val dragAndDropTarget = remember {object: DragAndDropTarget {// Highlights the border of a potential drop targetoverride fun onStarted(event: DragAndDropEvent) {showTargetBorder = true}override fun onEnded(event: DragAndDropEvent) {showTargetBorder = false}override fun onDrop(event: DragAndDropEvent): Boolean {// Prints the type of action into system output every time// a drag-and-drop operation is concluded.println("Action at the target: ${event.action}")val result = (targetText == "Drop here")// Changes the text to the value dropped into the composable.targetText = event.awtTransferable.let {if (it.isDataFlavorSupported(DataFlavor.stringFlavor))it.getTransferData(DataFlavor.stringFlavor) as Stringelseit.transferDataFlavors.first().humanPresentableName}// Reverts the text of the drop target to the initial// value after 2 seconds.coroutineScope.launch {delay(2000)targetText = "Drop here"}return result}}
}Box(Modifier.size(200.dp).background(Color.LightGray).then(if (showTargetBorder)Modifier.border(BorderStroke(3.dp, Color.Black))elseModifier).dragAndDropTarget(// With "true" as the value of shouldStartDragAndDrop,// drag-and-drop operations are enabled unconditionally.shouldStartDragAndDrop = { true },target = dragAndDropTarget)
) {Text(targetText, Modifier.align(Alignment.Center))
}