[SwiftUI] SwiftUI で実装する Drag&Drop (その2:クラスオブジェクト を Drag&Drop)

SwiftUI

Drag&Drop 実装について まとめていきます。今回は、自分で定義したクラスオブジェクトを ドラッグ&ドロップに対応させる方法です。

環境&対象

以下の環境で動作確認を行なっています。

  • macOS Big Sur 11.2.3
  • Xcode 12.4
SwiftUI[SwiftUI] SwiftUI で実装する Drag&Drop (その1: String を Drag&Drop)

自分で定義したクラスの対応

前回は、onDrag, onDrop で定義した closure の中で、NSItemProvider 経由で渡すデータの作成を行なって、ドラッグ&ドロップを実現していました。

自分の定義したクラスを使う時には、これらの処理を自クラスの中に入れ込むことができます。

クラスオブジェクトを受け渡しするためのプロトコル NSItemProviderReading, NSItemProviderWriting

独自に定義したクラスも、前回説明した方法で Data に変換することで、受け渡しすることができますが、もう1つ別の方法もあります。

そのための Protocol として、NSItemProviderReading と NSItemProviderWriting があります。

NSItemProviderReading は、ドロップされたときに オブジェクトを構築するために使用されます。(ドロップ時に、NSItemProvider から オブジェクトを受け取れるようにします)

NSItemProviderWriting は、ドラッグするときに、オブジェクトを提供するために使用されます。(ドラッグ時に、NSItemProvider に オブジェクトを提供できるようにします)

# いずれも、実際のデータ受け渡しは、ドラッグ&ドロップ操作が実行された時になります。

ベースとするクラス

example
コード解説
  1. NSItemProviderReading, NSItemProviderWriting に準拠するためには、class であることが必要で、NSObject を継承していないといけません。
  2. UTType として、”public.utf8-plain-text” を利用しています。
    独自定義のものを使うには追加手順が必要になるので省略のためです
  3. String を保持するだけのクラスです。

このクラスに、NSItemProviderReading, NSItemProviderWriting を実装していきます。

エラー処理のために以下のような enum を定義していますが、強い関係はありません。

example

NSItemProviderReading

定義しなければいけないものは2つです。「受け取ることができるタイプ」と「受け取ってと言われた時のデータ受け取り方法」です。
それぞれ、static var readableTypeIdentifiersForItemProvider と static func object(withItemProviderData data: Data, typeIdentifier: String) を定義することで設定します。

Apple のドキュメントは、こちら

NSItemProviderReading
コード解説
  1. readableTypeIdentifiersForItemProvider として、 “public.utf8-plain-text” を指定しています
  2. この関数が、ドロップされたときに、onDrop 内で ドラッグ&ドロップのデータからクラスを構築するために使用されるメソッドです。(static です)
  3. タイプをチェックして、想定していないタイプであればエラーとします
  4. 渡されるデータから String を復元し、MyDropData クラスのインスタンスを作成して返しています
オブジェクトの構築は、上記のように static メソッドの中で行われるため、必要な情報は全て、ドラッグ&ドロップ時のデータに含めておく必要があります。

NSItemProviderWriting

Reading と同様に定義しなければいけないものは2つです。「渡すことができるタイプ」と「渡してと言われた時にデータを渡す方法」です。
それぞれ、static var writableTypeIdentifiersForItemProvider と func loadData(withTypeIdentifier typeIdentifier: String, forItemProviderCompletionHandler completionHandler: @escaping (Data?, Error?) -> Void) -> Progress? を定義することで定義します。

Apple のドキュメントは、こちら

NSItemProviderWriting
コード解説
  1. String を受け渡すために、String を Data 化しています
  2. completionHandler 経由で、Data を受け手に渡します
  3. Progress を返すことで途中でのキャンセル等にも対応させることが可能です

NSItemProviderReading/NSItemProviderWriting の有無で比較

機能的に差異はありませんが、コードを並べておきます。

NSItemProviderReading

NSItemProviderReading

NSItemProviderWriting

NSItemProviderWriting

テストコード全体

前回のコードに今回のコードを追加した最終形は以下の通りです。

MyDropData,ContentView, MyError

注意
UTType として、public.utf8-plain-text を間借りしているので、気をつけてください。

まとめ:自分で定義したクラスのドラッグ&ドロップ対応

自分で定義したクラスのドラッグ&ドロップ対応
  • NSItemProviderReading に準拠することで、Drag 時に、オブジェクトを渡すことで、NSItemProvider が 対応タイプ含め自動で処理してくれる
  • NSItemProviderReading に準拠することで、Drop 時に、NSItemProvider から オブジェクトとして受け取ることが可能となる

説明は以上です。
不明な点やおかしな点ありましたら、こちらまで。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です