Drag and Drop Tutorial for macOS
をテンプレートにして作成
[
トップ
] [
新規
|
一覧
|
検索
|
最終更新
|
ヘルプ
|
ログイン
]
開始行:
&tag(Drag and Drop Tutorial for macOS);
*目次 [#ucabbfd7]
#contents
*関連ページ [#qaf5514b]
*参考情報 [#bc66b812]
-[[Drag and Drop Tutorial for macOS:https://www.raywender...
-NSViewサブクラスのドラッグ&ドロップ実装
-アプリのその他のビューにドラッグできるデータを提供
-カスタムドラッグタイプ
*Getting Started [#laf58f4a]
-同ページからスタータープロジェクトをダウンロード。
-メインのSticker Viewは画像などをドラッグ先。
-画面下部の二つのビューはデータソース。
-Dragging DestinationとDragging Sourcesに大別できる。
-Dragging Destination
--StickerBoardViewController.swift: メインビューコントロ...
--DestinationView.swift: 画面上部のビュー
-Dragging Source
--ImageSourceView.swift: ユニコーンのイメージがついたビュ...
--AppActionSourceView.swift Sparklesというラベルがつい他...
*ペーストボードとドラッギングセッション [#jd409a75]
-ドラッグとドロップはソースとデスティネーションが関連する。
-sourceからドラッグし、NSDraggingSourceプロトコルを実装す...
-destinationにドロップし、NSDraggingDestinationプロトコル...
-NSPasteboardはデータ交換を円滑する。
*Dragging Destinationの作成 [#lc882280]
-Dragging Destinationは、dragging pasteboardからのデータ...
-NSDraggingDestinationを実装する。
-手順
--ビュー構築時にdragging sessionから受け取るデータ型を宣...
--dragging imageがビューに入ったとき、ビューがデータを受...
--dragging imageがビューの上になったら、ビューの上でその...
-実装
- DestinationView.swiftを開き、setup()含め以下のように変...
#pre{{
var acceptableTypes: Set<String> { return [NSURLPboardTyp...
func setup() {
register(forDraggedTypes: Array(acceptableTypes))
}
}}
-さらに以下を追加(ドラッグエンターで呼び出される内部処理)。
#pre{{
//1.受け入れるタイプ。
let filteringOptions = [NSPasteboardURLReadingContentsC...
func shouldAllowDrag(_ draggingInfo: NSDraggingInfo) ->...
var canAccept = false
//2.ペーストボードを取得
let pasteBoard = draggingInfo.draggingPasteboard()
//3.ペーストボードのデータが読み取れるかどうかを決定
if pasteBoard.canReadObject(forClasses: [NSURL.self],...
canAccept = true
}
return canAccept
}
}}
-NSViewはNSDraggingDestinationを実装している。このメソッ...
-まずdraggingEnteredを実装する。
#pre{{
//1.ドラッグを受け入れるかどうか
var isReceivingDrag = false {
didSet {
needsDisplay = true
}
}
//2.ドラッグがエンター為たときの処理
override func draggingEntered(_ sender: NSDraggingInfo)...
let allow = shouldAllowDrag(sender)
isReceivingDrag = allow
return allow ? .copy : NSDragOperation()
}
}}
-exit処理の作成
#pre{{
override func draggingExited(_ sender: NSDraggingInfo?) {
isReceivingDrag = false
}
}}
-描画処理の変更
#pre{{
override func draw(_ dirtyRect: NSRect) {
if isReceivingDrag {
NSColor.selectedControlColor.set()
let path = NSBezierPath(rect:bounds)
path.lineWidth = Appearance.lineWidth
path.stroke()
}
}
}}
-ここまでで画像をドラッグしたらカーソルが+にかわり、外に...
-最後にデータを受け取る処理
-DestinationViewに以下を追加
#pre{{
override func prepareForDragOperation(_ sender: NSDraggin...
let allow = shouldAllowDrag(sender)
return allow
}
override func performDragOperation(_ draggingInfo: NSDr...
//1.ドラッグ中フラグをリセット
isReceivingDrag = false
let pasteBoard = draggingInfo.draggingPasteboard()
//2.ドロップポイントを取得
let point = convert(draggingInfo.draggingLocation(), ...
//3.データ処理
if let urls = pasteBoard.readObjects(forClasses: [NSU...
delegate?.processImageURLs(urls, center: point)
return true
}
return false
}
}}
-StickerBoardViewController.swiftを開き、以下のメソッドを...
#pre{{
func processImage(_ image: NSImage, center: NSPoint) {
//1.ラベルを非表示にする
invitationLabel.isHidden = true
//2.サイズを取得
let constrainedSize = image.aspectFitSizeForMaxDimens...
//3.NSImageViewを作成して追加
let subview = NSImageView(frame:NSRect(x: center.x - ...
subview.image = image
targetLayer.addSubview(subview)
//4.ランダム
let maxrotation = CGFloat(arc4random_uniform(Appearan...
subview.frameCenterRotation = maxrotation
}
}}
-以下のイメージも追加。
#pre{{
func processImageURLs(_ urls: [URL], center: NSPoint) {
for (index,url) in urls.enumerated() {
//1.イメージを作成
if let image = NSImage(contentsOf:url) {
var newCenter = center
//2.一つ伊集か
if index > 0 {
newCenter = center.addRandomNoise(Appearance.ra...
}
//3.画像処理
processImage(image, center:newCenter)
}
}
}
}}
*Dragging Sourceの作成 [#iba71ca8]
-ドラッグ元はNSDraggingSourceプロトコルを実装する必要があ...
-ImageSourceViewはユニコーンを持つビュー。ユニコーンをド...
-クラスはNSDraggingSourceとNSPasteboardItemDataProviderを...
-ImageSourceView.swiftに以下のメソッドを実装する。
#pre{{
// MARK: - NSDraggingSource
extension ImageSourceView: NSDraggingSource {
//1.NSDraggingSourceに必要。どのようなドラッグ操作を実...
func draggingSession(_ session: NSDraggingSession, sour...
return .generic
}
}
// MARK: - NSDraggingSource
extension ImageSourceView: NSPasteboardItemDataProvider {
//2.この段階ではスタブ
func pasteboard(_ pasteboard: NSPasteboard?, item: NSPa...
//TODO: Return image data
}
}
}}
-ドラッグの開始。
-ImageSourceViewに以下を実装する。
#pre{{
override func mouseDown(with theEvent: NSEvent) {
//1.ペーストボードアイテムを生成(要求に応じてデータを...
let pasteboardItem = NSPasteboardItem()
pasteboardItem.setDataProvider(self, forTypes: [kUTTy...
//2.ドラッギングデータを生成
let draggingItem = NSDraggingItem(pasteboardWriter: p...
draggingItem.setDraggingFrame(self.bounds, contents:s...
//3.ドラッギングセッションを開始
beginDraggingSession(with: [draggingItem], event: the...
}
}}
-この段階でユニコーンがドラッグできるようになる。
-これを受け入れるためにはDestinationView.swiftでTIFFを受...
#pre{{
var nonURLTypes: Set<String> { return [String(kUTTypeTIF...
var acceptableTypes: Set<String> { return nonURLTypes.uni...
}}
-setupを変更。
#pre{{
register(forDraggedTypes: Array(nonURLTypes))
}}
-shouldAllowDragを変更する。
#pre{{
else if let types = pasteBoard.types, nonURLTypes.interse...
canAccept = true
}}
-performDragOperationw変更する
#pre{{
else if let image = NSImage(pasteboard: pasteBoard) {
delegate?.processImage(image, center: point)
return true
}
}}
-この段階でドラッグすると+が表示されるようになる。
-実際にデータを追加できるようにするため、ImageSourceView....
#pre{{
func pasteboard(_ pasteboard: NSPasteboard?, item: NSPa...
//1.
if let pasteboard = pasteboard, type == String(kUTTyp...
//2.
let finalImage = image.tintedImageWithColor(NSColor...
//3.
let tiffdata = finalImage.tiffRepresentation
pasteboard.setData(tiffdata, forType:type)
}
}
}}
-さまざまな色のユニコーンが追加できるようになる。
*カスタムデータのドラッグ [#ub2f8668]
-カスタムデータソースの実装。新しいデータタイプ。
-AppActionSourceView.swiftを開く。
#pre{{
enum SparkleDrag {
static let type = "com.razeware.StickerDrag.AppAction"
static let action = "make sparkles"
}
}}
-ドラッグデータソースはUTIで表す。
-AppActionSourceViewに以下を実装。
#pre{{
// MARK: - NSDraggingSource// MARK: - NSDraggingSource
extensionextension AppActionSourceViewAppActionSourceVi...
{
funcfunc draggingSessiondraggingSession((__ session: ...
context: NSDraggingContext) session: NSDraggingSessio...
switch(context) {
case .outsideApplication:
return NSDragOperation()
case .withinApplication:
return .generic
}
}
}
}}
-アプリ外にはドロップできないようになっている。
-AppActionSourceViewにmouseDownを実装。
#pre{{
override func mouseDown(with theEvent: NSEvent) {
let pasteboardItem = NSPasteboardItem()
pasteboardItem.setString(SparkleDrag.action, forType: S...
let draggingItem = NSDraggingItem(pasteboardWriter: pas...
draggingItem.setDraggingFrame(self.bounds, contents:sna...
beginDraggingSession(with: [draggingItem], event: theEv...
}
}}
-新しいタイプを受け入れる。DestinationView.swiftを変更す...
#pre{{
var nonURLTypes: Set<String> { return [String(kUTTypeT...
}}
-performDragOperation新しいelseifを追加。
#pre{{
else if let types = pasteBoard.types, types.contains(Spar...
let action = pasteBoard.string(forType: SparkleDrag.typ...
delegate?.processAction(action, center:point)
return true
}
}}
-StickerBoardViewControllerにprocessActionを実装。
#pre{{
func processAction(_ action: String, center: NSPoint) {
//1.アクションを確認
if action == SparkleDrag.action {
invitationLabel.isHidden = true
//2.画像を生成
if let image = NSImage(named:"star") {
//3.
for _ in 1..<Appearance.numStars {
//A.
let maxSize:CGFloat = Appearance.maxStarSize
let sizeChange = CGFloat(arc4random_uniform(App...
let finalSize = maxSize - sizeChange
let newCenter = center.addRandomNoise(Appearanc...
//B.
let imageFrame = NSRect(x: newCenter.x, y: newC...
let imageView = NSImageView(frame:imageFrame)
//C.
let newImage = image.tintedImageWithColor(NSCol...
//D.
imageView.image = newImage
targetLayer.addSubview(imageView)
}
}
}
}
}}
終了行:
&tag(Drag and Drop Tutorial for macOS);
*目次 [#ucabbfd7]
#contents
*関連ページ [#qaf5514b]
*参考情報 [#bc66b812]
-[[Drag and Drop Tutorial for macOS:https://www.raywender...
-NSViewサブクラスのドラッグ&ドロップ実装
-アプリのその他のビューにドラッグできるデータを提供
-カスタムドラッグタイプ
*Getting Started [#laf58f4a]
-同ページからスタータープロジェクトをダウンロード。
-メインのSticker Viewは画像などをドラッグ先。
-画面下部の二つのビューはデータソース。
-Dragging DestinationとDragging Sourcesに大別できる。
-Dragging Destination
--StickerBoardViewController.swift: メインビューコントロ...
--DestinationView.swift: 画面上部のビュー
-Dragging Source
--ImageSourceView.swift: ユニコーンのイメージがついたビュ...
--AppActionSourceView.swift Sparklesというラベルがつい他...
*ペーストボードとドラッギングセッション [#jd409a75]
-ドラッグとドロップはソースとデスティネーションが関連する。
-sourceからドラッグし、NSDraggingSourceプロトコルを実装す...
-destinationにドロップし、NSDraggingDestinationプロトコル...
-NSPasteboardはデータ交換を円滑する。
*Dragging Destinationの作成 [#lc882280]
-Dragging Destinationは、dragging pasteboardからのデータ...
-NSDraggingDestinationを実装する。
-手順
--ビュー構築時にdragging sessionから受け取るデータ型を宣...
--dragging imageがビューに入ったとき、ビューがデータを受...
--dragging imageがビューの上になったら、ビューの上でその...
-実装
- DestinationView.swiftを開き、setup()含め以下のように変...
#pre{{
var acceptableTypes: Set<String> { return [NSURLPboardTyp...
func setup() {
register(forDraggedTypes: Array(acceptableTypes))
}
}}
-さらに以下を追加(ドラッグエンターで呼び出される内部処理)。
#pre{{
//1.受け入れるタイプ。
let filteringOptions = [NSPasteboardURLReadingContentsC...
func shouldAllowDrag(_ draggingInfo: NSDraggingInfo) ->...
var canAccept = false
//2.ペーストボードを取得
let pasteBoard = draggingInfo.draggingPasteboard()
//3.ペーストボードのデータが読み取れるかどうかを決定
if pasteBoard.canReadObject(forClasses: [NSURL.self],...
canAccept = true
}
return canAccept
}
}}
-NSViewはNSDraggingDestinationを実装している。このメソッ...
-まずdraggingEnteredを実装する。
#pre{{
//1.ドラッグを受け入れるかどうか
var isReceivingDrag = false {
didSet {
needsDisplay = true
}
}
//2.ドラッグがエンター為たときの処理
override func draggingEntered(_ sender: NSDraggingInfo)...
let allow = shouldAllowDrag(sender)
isReceivingDrag = allow
return allow ? .copy : NSDragOperation()
}
}}
-exit処理の作成
#pre{{
override func draggingExited(_ sender: NSDraggingInfo?) {
isReceivingDrag = false
}
}}
-描画処理の変更
#pre{{
override func draw(_ dirtyRect: NSRect) {
if isReceivingDrag {
NSColor.selectedControlColor.set()
let path = NSBezierPath(rect:bounds)
path.lineWidth = Appearance.lineWidth
path.stroke()
}
}
}}
-ここまでで画像をドラッグしたらカーソルが+にかわり、外に...
-最後にデータを受け取る処理
-DestinationViewに以下を追加
#pre{{
override func prepareForDragOperation(_ sender: NSDraggin...
let allow = shouldAllowDrag(sender)
return allow
}
override func performDragOperation(_ draggingInfo: NSDr...
//1.ドラッグ中フラグをリセット
isReceivingDrag = false
let pasteBoard = draggingInfo.draggingPasteboard()
//2.ドロップポイントを取得
let point = convert(draggingInfo.draggingLocation(), ...
//3.データ処理
if let urls = pasteBoard.readObjects(forClasses: [NSU...
delegate?.processImageURLs(urls, center: point)
return true
}
return false
}
}}
-StickerBoardViewController.swiftを開き、以下のメソッドを...
#pre{{
func processImage(_ image: NSImage, center: NSPoint) {
//1.ラベルを非表示にする
invitationLabel.isHidden = true
//2.サイズを取得
let constrainedSize = image.aspectFitSizeForMaxDimens...
//3.NSImageViewを作成して追加
let subview = NSImageView(frame:NSRect(x: center.x - ...
subview.image = image
targetLayer.addSubview(subview)
//4.ランダム
let maxrotation = CGFloat(arc4random_uniform(Appearan...
subview.frameCenterRotation = maxrotation
}
}}
-以下のイメージも追加。
#pre{{
func processImageURLs(_ urls: [URL], center: NSPoint) {
for (index,url) in urls.enumerated() {
//1.イメージを作成
if let image = NSImage(contentsOf:url) {
var newCenter = center
//2.一つ伊集か
if index > 0 {
newCenter = center.addRandomNoise(Appearance.ra...
}
//3.画像処理
processImage(image, center:newCenter)
}
}
}
}}
*Dragging Sourceの作成 [#iba71ca8]
-ドラッグ元はNSDraggingSourceプロトコルを実装する必要があ...
-ImageSourceViewはユニコーンを持つビュー。ユニコーンをド...
-クラスはNSDraggingSourceとNSPasteboardItemDataProviderを...
-ImageSourceView.swiftに以下のメソッドを実装する。
#pre{{
// MARK: - NSDraggingSource
extension ImageSourceView: NSDraggingSource {
//1.NSDraggingSourceに必要。どのようなドラッグ操作を実...
func draggingSession(_ session: NSDraggingSession, sour...
return .generic
}
}
// MARK: - NSDraggingSource
extension ImageSourceView: NSPasteboardItemDataProvider {
//2.この段階ではスタブ
func pasteboard(_ pasteboard: NSPasteboard?, item: NSPa...
//TODO: Return image data
}
}
}}
-ドラッグの開始。
-ImageSourceViewに以下を実装する。
#pre{{
override func mouseDown(with theEvent: NSEvent) {
//1.ペーストボードアイテムを生成(要求に応じてデータを...
let pasteboardItem = NSPasteboardItem()
pasteboardItem.setDataProvider(self, forTypes: [kUTTy...
//2.ドラッギングデータを生成
let draggingItem = NSDraggingItem(pasteboardWriter: p...
draggingItem.setDraggingFrame(self.bounds, contents:s...
//3.ドラッギングセッションを開始
beginDraggingSession(with: [draggingItem], event: the...
}
}}
-この段階でユニコーンがドラッグできるようになる。
-これを受け入れるためにはDestinationView.swiftでTIFFを受...
#pre{{
var nonURLTypes: Set<String> { return [String(kUTTypeTIF...
var acceptableTypes: Set<String> { return nonURLTypes.uni...
}}
-setupを変更。
#pre{{
register(forDraggedTypes: Array(nonURLTypes))
}}
-shouldAllowDragを変更する。
#pre{{
else if let types = pasteBoard.types, nonURLTypes.interse...
canAccept = true
}}
-performDragOperationw変更する
#pre{{
else if let image = NSImage(pasteboard: pasteBoard) {
delegate?.processImage(image, center: point)
return true
}
}}
-この段階でドラッグすると+が表示されるようになる。
-実際にデータを追加できるようにするため、ImageSourceView....
#pre{{
func pasteboard(_ pasteboard: NSPasteboard?, item: NSPa...
//1.
if let pasteboard = pasteboard, type == String(kUTTyp...
//2.
let finalImage = image.tintedImageWithColor(NSColor...
//3.
let tiffdata = finalImage.tiffRepresentation
pasteboard.setData(tiffdata, forType:type)
}
}
}}
-さまざまな色のユニコーンが追加できるようになる。
*カスタムデータのドラッグ [#ub2f8668]
-カスタムデータソースの実装。新しいデータタイプ。
-AppActionSourceView.swiftを開く。
#pre{{
enum SparkleDrag {
static let type = "com.razeware.StickerDrag.AppAction"
static let action = "make sparkles"
}
}}
-ドラッグデータソースはUTIで表す。
-AppActionSourceViewに以下を実装。
#pre{{
// MARK: - NSDraggingSource// MARK: - NSDraggingSource
extensionextension AppActionSourceViewAppActionSourceVi...
{
funcfunc draggingSessiondraggingSession((__ session: ...
context: NSDraggingContext) session: NSDraggingSessio...
switch(context) {
case .outsideApplication:
return NSDragOperation()
case .withinApplication:
return .generic
}
}
}
}}
-アプリ外にはドロップできないようになっている。
-AppActionSourceViewにmouseDownを実装。
#pre{{
override func mouseDown(with theEvent: NSEvent) {
let pasteboardItem = NSPasteboardItem()
pasteboardItem.setString(SparkleDrag.action, forType: S...
let draggingItem = NSDraggingItem(pasteboardWriter: pas...
draggingItem.setDraggingFrame(self.bounds, contents:sna...
beginDraggingSession(with: [draggingItem], event: theEv...
}
}}
-新しいタイプを受け入れる。DestinationView.swiftを変更す...
#pre{{
var nonURLTypes: Set<String> { return [String(kUTTypeT...
}}
-performDragOperation新しいelseifを追加。
#pre{{
else if let types = pasteBoard.types, types.contains(Spar...
let action = pasteBoard.string(forType: SparkleDrag.typ...
delegate?.processAction(action, center:point)
return true
}
}}
-StickerBoardViewControllerにprocessActionを実装。
#pre{{
func processAction(_ action: String, center: NSPoint) {
//1.アクションを確認
if action == SparkleDrag.action {
invitationLabel.isHidden = true
//2.画像を生成
if let image = NSImage(named:"star") {
//3.
for _ in 1..<Appearance.numStars {
//A.
let maxSize:CGFloat = Appearance.maxStarSize
let sizeChange = CGFloat(arc4random_uniform(App...
let finalSize = maxSize - sizeChange
let newCenter = center.addRandomNoise(Appearanc...
//B.
let imageFrame = NSRect(x: newCenter.x, y: newC...
let imageView = NSImageView(frame:imageFrame)
//C.
let newImage = image.tintedImageWithColor(NSCol...
//D.
imageView.image = newImage
targetLayer.addSubview(imageView)
}
}
}
}
}}
ページ名: