カテゴリー
iOS Swift

Drag and Dropを学ぶ

参考

【概要】

ドラッグはUIエレメントに対するロングプレスをトリガーとして開始され、プレヴューイメージが表示され、drag session (UIDragSession)が開始される。drag sessionはドラッグ動作が完了もしくはキャンセルされるまで維持される。

プレヴューイメージはDestinationまでドラッグされる。Destinationがドラッグされたアイテムの型を扱える場合はその旨の表示がなされる。

ViewControllerにはdrag delegateやdrop delegateがアサインされる。

ViewController内のドラッグされる個別のviewはinteraction objectsを持つ必要がある。drag source(ドラッグ元)のviewはUIDragInteractionを、drag destination(ドラッグ先)のviewはUIDropInteractionを持つ。これらのInteractionには幅広いレンジのdelegateメソッドがあり、実装に応じてドラッグ・ドロップ・ライフサイクル内の様々な時点で呼ばれる。

各ドラッグ動作はdrag item (UIDragItem)で表される。drag itemはプレヴューイメージやitem provider (UIItemProvider)を持つ。item providerは移動対象のアイテムに関する情報を持ち、それはドロップが実施される場合の非同期トランスファーに使用される。

以下はdrag sourceとdrag destinationの最小コード

import UIKit

class ViewController: UIViewController {

  var stringArray: [String] = [] {
    didSet {
      print(stringArray)
    }
  }
  
  lazy var dragSource: UIView = {
    let view = UIView()
    let dragInteraction = UIDragInteraction(delegate: self)
    view.addInteraction(dragInteraction)
    return view
  }()
  
  lazy var dragDestination: UIView = {
    let view = UIView()
    let dropInteraction = UIDropInteraction(delegate: self)
    view.addInteraction(dropInteraction)
    return view
  }()
  
  override func viewDidLoad() {
    super.viewDidLoad()
    
    view.backgroundColor = .white
    view.addSubview(dragSource)
    view.addSubview(dragDestination)
  }
  
  override func viewWillLayoutSubviews() {
    super.viewWillLayoutSubviews()
    layout()
  }
  
  func layout() {
    // dragSource
    let itemSize: CGFloat = 100
    dragSource.frame = CGRect(x: view.bounds.width/2 - itemSize/2, y: view.bounds.height/2 - itemSize/2, width: itemSize, height: itemSize)
    dragSource.backgroundColor = .red
    // dragDestination
    dragDestination.frame = CGRect(x: view.bounds.width/2 - itemSize/2, y: view.bounds.height - itemSize/2 - 200, width: itemSize, height: itemSize)
    dragDestination.backgroundColor = .blue
  }
}

extension ViewController: UIDragInteractionDelegate {
  func dragInteraction(_ interaction: UIDragInteraction, itemsForBeginning session: UIDragSession) -> [UIDragItem] {
    let localObject = CustomClass(name: "me")
    let stringItemProvider = NSItemProvider(object: "Hello" as NSString)
    let item = UIDragItem(itemProvider: stringItemProvider)
    item.localObject = localObject
    return [
      item
    ]
  }
}

extension ViewController: UIDropInteractionDelegate {
  func dropInteraction(_ interaction: UIDropInteraction, canHandle session: UIDropSession) -> Bool {
    return true
  }
  
  func dropInteraction(_ interaction: UIDropInteraction, sessionDidEnd session: UIDropSession) {
    let dropLocation = session.location(in: view)
    
  }
}

class CustomClass {

  var name: String
  
  init(name: String) {
    self.name = name
  }
  
}