ドラッグ&ドロップ操作
現在、Web版Compose Multiplatformではドラッグ&ドロップ操作はサポートされていません。 今後のリリースにご期待ください。
Compose Multiplatformアプリで、ユーザーが他のアプリケーションからドラッグしてきたデータを受け入れたり、ユーザーがアプリからデータをドラッグして持ち出せるようにしたりすることができます。 これを実装するには、dragAndDropSource
および dragAndDropTarget
修飾子を使用して、特定のコンポーザブルをドラッグ操作の潜在的なソースまたはターゲットとして指定します。
dragAndDropSource
およびdragAndDropTarget
修飾子はどちらも実験的なものであり、変更される可能性があり、オプトインアノテーションが必要です。
ドラッグソースの作成
コンポーザブルをドラッグソースとして準備するには:
detectDragGestures()
関数(例:onDragStart
)でドラッグイベントのトリガーを選択します。startTransfer()
関数を呼び出し、DragAndDropTransferData()
を呼び出してドラッグ&ドロップセッションを記述します。DragAndDropTransferable()
を呼び出して、ターゲットにドラッグされるデータを記述します。
ユーザーが文字列をドラッグできるBox()
コンポーザブルの例を次に示します。
kotlin
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))
}
ドロップターゲットの作成
コンポーザブルをドラッグ&ドロップターゲットとして準備するには:
shouldStartDragAndDrop
ラムダで、コンポーザブルがドロップのターゲットとなる条件を記述します。- ドラッグイベントハンドラのオーバーライドを含む
DragAndDropTarget
オブジェクトを作成し(そしてremember
し)ます。 - 必要なオーバーライドを記述します。例えば、受信したデータを解析するための
onDrop
や、ドラッグ可能なオブジェクトがコンポーザブルに入ったときのonEntered
などです。
ドロップされたテキストを表示する準備ができている Box()
コンポーザブルの例を次に示します。
kotlin
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 ドキュメントの対応する修飾子に関するドラッグ&ドロップの記事を参照してください。