今回はNSTableView
内の行をドラッグで移動させてみます。
やること
- ドラッグ元の行番号をPasteboardに保存する。
- ドロップされた時に、そのドロップを受け入れるかチェック。
- ドロップを受け入れたら、Pasteboardに保存していたドラッグ元の行番号を取り出して、ドロップ先と入れ替えるなど。
3では用途に応じて、移動元の行と移動先の行に対して自由に操作を行います。
今回は、移動元と移動先を「入れ替える」挙動にしてみました。
実装
NSTableViewDataSourceの以下3つを実装します。
- tableView(_:writeRowsWith:to:)
- tableView(_:validateDrop:proposedRow:proposedDropOperation:)
- tableView(_:acceptDrop:row:dropOperation:)
1. ドラッグ元の行番号をPasteboardに保存する
func tableView(_ tableView: NSTableView, writeRowsWith rowIndexes: IndexSet, to pboard: NSPasteboard) -> Bool { // Pasteboardにドラッグ元の行情報を記録 let data = NSKeyedArchiver.archivedData(withRootObject: rowIndexes) let item = NSPasteboardItem.init() item.setData(data, forType: draggingUTIType) pboard.writeObjects([item]) return true }
ペーストボードを使う所が少々トリッキーだなと感じました。
2. ドロップされた時に、そのドロップを受け入れるかチェック
func tableView(_ tableView: NSTableView, validateDrop info: NSDraggingInfo, proposedRow row: Int, proposedDropOperation dropOperation: NSTableViewDropOperation) -> NSDragOperation { // 今回は、同じTableViewからのDropのみを受け付ける guard let source = info.draggingSource() as? NSTableView, source === tableView else { return [] } return .move }
例えば、別のウィンドウからファイルをドロップするような場合もここに入ります。 ファイルのドロップを受け入れたい時、または受け入れたくない時は、ここで許可や拒否をします。
.move
を返す:ドロップを受け入れる[]
を返す:ドロップを受け入れない
NSDragOperation
今回は「移動」させたいのでNSDragOperation.move
を返しています。
NSDragOperationには、他にも.copy
などの操作があるので、移動以外にも使えるようです。(試していません)
3. ドロップを受け入れた後の処理
func tableView(_ tableView: NSTableView, acceptDrop info: NSDraggingInfo, row: Int, dropOperation: NSTableViewDropOperation) -> Bool { // ドラッグされたアイテムのUTI typeを確認 guard let item = info.draggingPasteboard().pasteboardItems?.first?.data(forType: draggingUTIType) else { return false } // Pasteboardに記録しておいたドラッグ元の行Noを取り出し guard let sourceRowIndexes = NSKeyedUnarchiver.unarchiveObject(with: item) as? IndexSet, let from = sourceRowIndexes.first else { return false } // ... 入れ替えの処理など ... return true }
- ドラッグされたアイテムのUTIを確認して整合性チェック
- Pasteboardに記録していたドラッグ元の行番号を取り出し
などしています。
ここではドロップ先の行番号が取得できるので、移動元と移動先の行番号を使ってデータの入れ替えなどを実装できます。
UTI
今回初めてUniform Type Identifiersの事を知りました。
サンプルではpublic.data
を指定しました。(誤っているかもしれません)
サンプル
以前にNSTableViewを試したサンプルに、ドラッグで行を入れ替えるコードを追加しました。
以上です!