Kotlin Multiplatform Development Help

拖放操作

您可以让 Compose Multiplatform 应用支持接收用户从其他应用拖入的数据,或允许用户从应用中拖出数据。
通过 dragAndDropSourcedragAndDropTarget 修饰符,可将特定组合项指定为拖拽操作的潜在来源或目标。

创建拖拽源

将组合项设为拖拽源的步骤:

  1. 使用 detectDragGestures() 函数选择拖拽事件触发器(如 onDragStart)。

  2. 调用 startTransfer() 函数,并通过 DragAndDropTransferData() 描述拖放会话。

  3. 使用 DragAndDropTransferable() 声明待拖拽至目标的数据。

以下示例展示允许用户拖拽字符串的 Box() 组合项:

val exportedText = "Hello, drag and drop!" Box(Modifier .dragAndDropSource( // 创建被拖拽数据的视觉呈现 // (白色矩形,中央显示 exportedText 字符串) 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( // 定义可传输数据及支持的传输动作 // 动作完成后通过 onTransferCompleted() 将结果输出至系统 DragAndDropTransferData( transferable = DragAndDropTransferable( StringSelection(exportedText) ), // 拖拽源支持的动作列表。动作类型会与数据 // 一同传递给放置目标,目标可据此拒绝不合适的操作 // 或解读用户意图 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)) }

创建放置目标

将组合项设为拖放目标的步骤:

  1. shouldStartDragAndDrop lambda 中描述成为放置目标的条件。

  2. 创建(并 remember )包含拖拽事件处理逻辑的 DragAndDropTarget 对象。

  3. 编写必要重写逻辑:如解析接收数据的 onDrop ,或可拖拽对象进入组合项时的 onEntered

以下示例展示可显示拖入文本的 Box() 组合项:

var showTargetBorder by remember { mutableStateOf(false) } var targetText by remember { mutableStateOf("Drop Here") } val coroutineScope = rememberCoroutineScope() val dragAndDropTarget = remember { object: DragAndDropTarget { // 高亮显示潜在放置目标的边框 override fun onStarted(event: DragAndDropEvent) { showTargetBorder = true } override fun onEnded(event: DragAndDropEvent) { showTargetBorder = false } override fun onDrop(event: DragAndDropEvent): Boolean { // 每次拖放操作结束时,将动作类型输出至系统 println("Action at the target: ${event.action}") val result = (targetText == "Drop here") // 将文本更改为拖入组合项的值 targetText = event.awtTransferable.let { if (it.isDataFlavorSupported(DataFlavor.stringFlavor)) it.getTransferData(DataFlavor.stringFlavor) as String else it.transferDataFlavors.first().humanPresentableName } // 2秒后将放置目标的文本恢复初始值 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)) else Modifier ) .dragAndDropTarget( // shouldStartDragAndDrop 设为 "true" 时 // 无条件启用拖放操作 shouldStartDragAndDrop = { true }, target = dragAndDropTarget ) ) { Text(targetText, Modifier.align(Alignment.Center)) }

后续步骤

关于实现细节和常见用例,请参阅 Jetpack Compose 文档中的
拖放操作一文。

22 四月 2025