compose foundation 1.6 で Experimentalだったドラッグ&ドロップ周りのModifierが来てたのでいくつか記事にします(させます)
dragAndDropSource
この機能を利用すると、任意のComposableにドラッグ動作を提供できます。以下に一般的なAPIの形式を示します。
@ExperimentalFoundationApi
fun Modifier.dragAndDropSource(
drawDragDecoration: DrawScope.() -> Unit,
block: suspend DragAndDropSourceScope.() -> Unit
): Modifier
例: 文字をドラッグ可能にする
下記のコンポーザブル関数例では、ドラッグして文字列の転送を開始するボックスが定義されています。
@Composable
fun DragAndDropSourceSample() {
val color = Color.Red
Box(
modifier = Modifier
.size(56.dp)
.background(color = color)
.dragAndDropSource(
drawDragDecoration = { drawRect(color) },
) { // DragAndDropSourceScope
detectTapGestures(
onLongPress = {
startTransfer( // 送るデータ
transferData = DragAndDropTransferData(
ClipData.newPlainText("text", "text"),
),
)
}
)
}
)
}
drawDragDecoration
はドラッグ中の視覚効果をDrawScopeで描画します。また、DragAndDropSourceScope
はPointerInputScope
が提供され、これを用いてどのジェスチャでstartTransfer
(データ転送)をするかを定義します。
dragAndDropTarget
を用いたドロップ操作の追加
ドラッグ対象に対して、以下のような形式でdragAndDropTarget
機能を追加することができます。
@ExperimentalFoundationApi
fun Modifier.dragAndDropTarget(
shouldStartDragAndDrop: (startEvent: DragAndDropEvent) -> Boolean,
target: DragAndDropTarget
): Modifier
アンカーを設定するDraggableAnchors
関数
@ExperimentalFoundationApi
fun <T : Any> DraggableAnchors(
builder: DraggableAnchorsConfig<T>.() -> Unit
): DraggableAnchors<T> = MapDraggableAnchors(DraggableAnchorsConfig<T>().apply(builder).anchors)
特定の位置にアンカーを設定し、そのアンカー間でのドラッグを可能にするDraggableAnchors
関数についても触れておくと良いでしょう。それにより、ユーザーは特定の範囲内でコントロールの移動を体験することができます。
DraggableAnchors {
T at 0f
T at 300f
}
上記のようにアンカーを設定し、anchoredDraggable
を使って制御することができます。
例えば、以下のコードはスタートとエンドの位置にアンカーを設定し、アイコンをそれらのアンカー間でドラッグできるようにしています。
enum class AnchorPos {
Start, End;
}
...
val density = LocalDensity.current
val draggableState = remember {
AnchoredDraggableState(
initialValue = AnchorPos.Start,
anchors = DraggableAnchors {
AnchorPos.Start at 0f
AnchorPos.End at 300f
},
positionalThreshold = { totalDistance -> totalDistance * 0.5f},
velocityThreshold = { with(density) { 100.dp.toPx()} },
animationSpec = tween(),
confirmValueChange = { true }
)
}
Box(modifier = Modifier.fillMaxSize()) {
Image(
imageVector = Icons.Default.FavoriteBorder,
contentDescription = "",
modifier = Modifier
.offset(
x = with(density) {
draggableState
.requireOffset()
.toDp()
}
)
.anchoredDraggable(
state = draggableState,
orientation = Orientation.Horizontal,
enabled = true,
reverseDirection = false,
interactionSource = null
)
.padding(start = 24.dp)
)
}
これらの機能を駆使することで、Jetpack Compose におけるユーザーインタラクションは一層豊かになります。機能の実装にあたっては、常にユーザビリティを考慮し、最適なユーザーエクスペリエンスを提供することが重要です。
終わり
この記事は、雑メモをGPT4に通して記事っぽくしてもらってます。
draggable2D, draggable もメモにあったのですが長すぎて削られた様子。