Skip to content

Instantly share code, notes, and snippets.

@sooop
Created February 9, 2017 06:07
Show Gist options
  • Star 12 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save sooop/3c964900d429516ba48bd75050d0de0a to your computer and use it in GitHub Desktop.
Save sooop/3c964900d429516ba48bd75050d0de0a to your computer and use it in GitHub Desktop.
NSTableView reordering row with drag and drop
//
// ViewController.swift
// DragTable
//
// Created by Anna Kim on 2017. 2. 9..
// Copyright © 2017년 Anna Kim. All rights reserved.
//
import Cocoa
// MARK: - Array Extension
// 원소의 위치 이동을 위한 Array 타입 확장
extension Array {
mutating func move(from start: Index, to end: Index) {
guard (0..<count) ~= start, (0...count) ~= end else { return }
if start == end { return }
let targetIndex = start < end ? end - 1 : end
insert(remove(at: start), at: targetIndex)
}
mutating func move(with indexes: IndexSet, to toIndex: Index) {
let movingData = indexes.map{ self[$0] }
let targetIndex = toIndex - indexes.filter{ $0 < toIndex }.count
for (i, e) in indexes.enumerated() {
remove(at: e - i)
}
insert(contentsOf: movingData, at: targetIndex)
}
}
// MARK: - View Controller Implementation
class ViewController: NSViewController {
var names = ["apple", "banana", "cherry", "orange", "pear", "peach" ]
@IBOutlet weak var sourceTableView: NSTableView!
override func viewDidLoad() {
super.viewDidLoad()
sourceTableView.register(forDraggedTypes: ["public.data"])
sourceTableView.allowsMultipleSelection = true
}
}
// MARK: - NSTableViewDataSource, NSTableViewDelegate
extension ViewController: NSTableViewDelegate, NSTableViewDataSource {
func numberOfRows(in tableView: NSTableView) -> Int {
return names.count
}
func tableView(_ tableView: NSTableView, objectValueFor tableColumn: NSTableColumn?, row: Int) -> Any? {
return names[row]
}
// MARK: Allow Drag Operation
/* tableView(_:writeRowsWith:to:) 를 구현하면서 true를 리턴하게 하면 해당 테이블 뷰에서 드래그가 가능해진다.
이때, 실제 데이터보다는 선택된 셀들의 인덱스들을 인코딩해버리는 것이 편하다.
*/
func tableView(_ tableView: NSTableView, writeRowsWith rowIndexes: IndexSet, to pboard: NSPasteboard) -> Bool {
let data = NSKeyedArchiver.archivedData(withRootObject: rowIndexes)
let item = NSPasteboardItem()
item.setData(data, forType: "public.data")
pboard.writeObjects([item])
return true
}
// MARK: Drag Destination Actions
func tableView(_ tableView: NSTableView, validateDrop info: NSDraggingInfo, proposedRow row: Int, proposedDropOperation dropOperation: NSTableViewDropOperation) -> NSDragOperation {
guard let source = info.draggingSource() as? NSTableView,
source === sourceTableView
else { return [] }
if dropOperation == .above {
return .move
}
return []
}
func tableView(_ tableView: NSTableView, acceptDrop info: NSDraggingInfo, row: Int, dropOperation: NSTableViewDropOperation) -> Bool {
let pb = info.draggingPasteboard()
if let itemData = pb.pasteboardItems?.first?.data(forType: "public.data"),
let indexes = NSKeyedUnarchiver.unarchiveObject(with: itemData) as? IndexSet
{
names.move(with: indexes, to: row)
let targetIndex = row - (indexes.filter{ $0 < row }.count)
// 드래그했던 셀들을 다시 선택 상태로 만들어 둔다.
tableView.selectRowIndexes(IndexSet(targetIndex..<targetIndex+indexes.count), byExtendingSelection: false)
return true
}
return false
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment