ドラッグ&ドロップ

Jetpack Compose は、次の 2 つの修飾子によるドラッグ&ドロップをサポートしています。

  • dragAndDropSource: ドラッグ ジェスチャーの開始点としてコンポーザブルを指定します。
  • dragAndDropTarget: ドロップされたデータを受け入れるコンポーザブルを指定します。

たとえば、ユーザーがアプリ内で画像をドラッグできるようにするには、画像コンポーザブルを作成し、dragAndDropSource 修飾子を追加します。ドロップ ターゲットを設定するには、別の画像コンポーザブルを作成し、dragAndDropTarget 修飾子を追加します。

修飾子は、複数のドラッグ ソースと複数のドロップ ターゲットに適用できます。

修飾子を使用すると、アプリは ClipData を使用して 2 つ以上のコンポーザブル間でデータを共有できます。これは View 実装と相互運用可能です。

ドラッグソースを指定する

コンポーネント内のドラッグ イベントを有効にするには、dragAndDropSource 修飾子を追加します。これは、関数をパラメータとして受け取ります。この関数内で、DragAndDropTransferData を使用して転送可能なデータを表します。データには、リモート URI、クリップボード上のリッチテキスト データ、ローカル ファイルなどがありますが、すべて ClipData オブジェクトでラップする必要があります。次のように書式なしテキストを指定します。

Modifier.dragAndDropSource { _ ->
    DragAndDropTransferData(
        ClipData.newPlainText(
            "image Url", url
        )
    )
}

ドラッグ アクションでアプリの境界を越えることができるようにするには、DragAndDropTransferData コンストラクタで flags 引数を受け取るようにします。次の例では、DRAG_FLAG_GLOBAL 定数で、データをあるアプリから別のアプリにドラッグできることを指定しています。

Modifier.dragAndDropSource { _ ->
    DragAndDropTransferData(
        ClipData.newPlainText(
            "image Url", url
        ),
        flags = View.DRAG_FLAG_GLOBAL
    )
}

DragAndDropTransferData は、Android ビューシステムでサポートされているフラグを受け入れます。使用可能なフラグの一覧については、View 定数のリストをご覧ください。

ドロップデータを受信する

コンポーザブルに dragAndDropTarget 修飾子を割り当てることで、コンポーザブルがドラッグ&ドロップ イベントを受信できるようにします。修飾子には 2 つのパラメータがあります。1 つ目はフィルタとして機能し、修飾子が受け入れることができるデータの種類を指定します。2 つ目は、コールバックでデータを配信します。

コールバック インスタンスは保持する必要があります。次のスニペットは、コールバックを記憶する方法を示しています。

val callback = remember {
    object : DragAndDropTarget {
        override fun onDrop(event: DragAndDropEvent): Boolean {
            // Parse received data
            return true
        }
    }
}

他のアプリからデータを受信するには、requestDragAndDropPermission を使用して受信を有効にし、完了したら解放します。

val externalAppCallback = remember {
    object : DragAndDropTarget {
        override fun onDrop(event: DragAndDropEvent): Boolean {
            val permission =
                activity.requestDragAndDropPermissions(event.toAndroidDragEvent())
            // Parse received data
            permission?.release()
            return true
        }
    }
}

Compose コールバックから返される DragAndDropEvent は、requestDragAndDropPermission メソッドで想定される DragAndDropEvent とは異なるため、権限リクエストに渡す前に、パラメータで toAndroidDragEvent() 拡張関数を呼び出す必要があります。

次のスニペットは、ドロップされたプレーン テキストを処理する方法を示しています。

Modifier.dragAndDropTarget(
    shouldStartDragAndDrop = { event ->
        event.mimeTypes().contains(ClipDescription.MIMETYPE_TEXT_PLAIN)
    }, target = callback // or externalAppCallback
)

コールバック関数は、イベントが消費された場合は true を返し、イベントが拒否され親コンポーネントに伝播されない場合は false を返す必要があります。

ドラッグ&ドロップ イベントを処理する

DragAndDropTarget インターフェースのコールバックをオーバーライドして、ドラッグ&ドロップ イベントの開始、終了、コンポーネントへの移動、コンポーネントからの移動を監視し、UI とアプリの動作を正確に制御します。

object : DragAndDropTarget {
    override fun onStarted(event: DragAndDropEvent) {
        // When the drag event starts
    }

    override fun onEntered(event: DragAndDropEvent) {
        // When the dragged object enters the target surface
    }

    override fun onEnded(event: DragAndDropEvent) {
        // When the drag event stops
    }

    override fun onExited(event: DragAndDropEvent) {
        // When the dragged object exits the target surface
    }

    override fun onDrop(event: DragAndDropEvent): Boolean = true
}

参考情報

Codelab: Compose でのドラッグ&ドロップ