
SwiftUIでドラッグ&ドロップの機能を実装する際、ドロップ処理の本体となる重要なメソッドが performDrop(info:)
です。
DropDelegate
プロトコルの中で唯一「必須」となっているこのメソッドは、ドロップが確定した瞬間に呼ばれ、データの受け渡しやリストの更新など、アクションの最終処理を担当します。
この記事では performDrop(info:)
の基本的な使い方から、引数 info
の意味、活用シーン、注意点までをわかりやすく丁寧に解説します。
performDrop(info:) とは?
performDrop(info:)
は、DropDelegate
プロトコルで定義されているメソッドで、ドロップが実行されたタイミングで呼び出される処理の本体です。
たとえば、他のリストからアイテムがドラッグされてきて、ドロップ先のビューに指が離された瞬間に performDrop
が発動します。
ここで、データをリストに追加したり、UIの状態を更新したりすることで、実際の「ドロップ動作」が完成します。
引数 info の意味
info
は DropInfo
型で、ドロップ時の状況に関する情報を持っています。
主に以下のプロパティやメソッドが利用できます:
info.location
: ドロップ位置の座標(ビュー内のCGPoint
)info.hasItemsConforming(to:)
: 指定したUTTypeのアイテムが含まれるかどうかinfo.itemProviders(for:)
: ドロップされたアイテムのNSItemProvider
配列を取得info.dropOperation
: ユーザーが選んだドロップの操作種別(move / copy など)
これらを使って、どんなアイテムがどこにドロップされたかを判断し、適切な処理を実行できます。
具体例:テキストデータをドロップで受け取る
まずはシンプルに、DropDelegate
を実装してテキストデータをドロップで受け取る例です:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
struct MyDropDelegate: DropDelegate { @Binding var items: [String] func performDrop(info: DropInfo) -> Bool { let providers = info.itemProviders(for: [.text]) for provider in providers { provider.loadItem(forTypeIdentifier: UTType.text.identifier, options: nil) { (data, error) in if let data = data as? Data, let text = String(data: data, encoding: .utf8) { DispatchQueue.main.async { items.append(text) } } } } return true } } |
この例では、ドロップされた text/plain
型のデータを読み込み、配列に追加しています。
非同期で NSItemProvider
からアイテムを読み出し、UI更新はメインスレッドで行う必要があります。
具体例:ドラッグ中のアイテムを別のリストに移動
2つのリスト間でアイテムを移動したい場合にも performDrop
が使われます。
たとえば「別リストから移動されたアイテムだけを受け入れる」といった条件処理を組み込むことも可能です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
func performDrop(info: DropInfo) -> Bool { guard let draggingItem = draggingItem else { return false } if draggingItem.originList != currentList { withAnimation { destinationList.append(draggingItem) sourceList.removeAll { $0.id == draggingItem.id } } return true } return false } |
このように、状態変数(@State
や @Binding
)と連携することで、View全体の整合性を保ったままドロップの効果を反映できます。
performDrop を使うときの注意点
performDrop
を実際に使う際には、いくつかの注意点を理解しておかないと UIが更新されない、期待通りにデータが扱えない といった問題が発生する可能性があります。
- 戻り値は Bool
true
を返すと「ドロップが受け入れられた」と見なされます。失敗したときはfalse
を返すこと。 - 非同期処理との相性に注意
NSItemProvider
の.loadItem
は非同期なので、データを受け取る処理をDispatchQueue.main.async
やTask { @MainActor in ... }
で包む必要があります。 - 状態更新はメインスレッドで行う
SwiftUIの状態更新(例:リストの追加や削除)は必ずメインスレッドで行いましょう。UIが更新されない、クラッシュするといった不具合を防げます。 - info.location を使ってドロップ位置に応じた挙動制御も可能
たとえばリスト中のどの位置にドロップされたかを見て、並び順の制御に使うこともできます。
performDrop(info:)
を安全かつ正しく使うためには、非同期処理の扱い方 と メインスレッドでのUI更新 が特に重要です。
さらに、info.location
を活用すれば「ただ受け取るだけ」ではなく、柔軟なドロップ体験をデザインできます。
まとめ
今回は SwiftUI の performDrop(info:)
について詳しく解説しました。
performDrop(info:)
は DropDelegate における「実際のドロップ処理」を担うメソッド- info にはドロップ位置やアイテムの内容などの情報が含まれる
- CSVやテキスト、カスタムデータなどさまざまな型に対応可能
- 非同期処理でアイテムを取り出す場合は UI更新とのスレッド整合性に注意
- リストの移動や確認ダイアログ表示など、高度な制御も可能
SwiftUIでドラッグ&ドロップに対応したインタラクティブなUIを構築するうえで、performDrop(info:)
の理解は欠かせません。
シンプルな受け取り処理から、複数リストのアイテム管理、ユーザー確認なども含めて、自在に活用できるようにしておきましょう。