Drag & Drop
Vamos dar uma olhada rápida no funcionamento do Drag & Drop – Arrastar e Soltar. Essa API é bem interessante e completa, por isso não deixe de conferir a documentação oficial para todos os detalhes de seu funcionamento e essa palestra da #WWDC17.
Drag
Para habilitar a interação de arrastar – em inglês drag – basta criar um UIDragInteraction
e adicioná-lo a view que desejamos arrastar. Repare que o procedimento é similar ao UIGestureRecognizer.
let drag = UIDragInteraction(delegate: self)
view.addInteraction(drag)
Na criação da interação atribuímos um delegate para receber os eventos, portanto temos que conformar com o protocolo UIDragInteractionDelegate
. O único método exigido é dragInteraction(_, itemsForBeginning:)
, nele devemos retornar o item que está sendo arrastado.
func dragInteraction(_ interaction: UIDragInteraction, itemsForBeginning session: UIDragSession) -> [UIDragItem] {
// Para passar o modelo do item arrastado usamos um `NSItemProvider`,
// como a API pede um objeto, vamos transformar a estrutura String da Swift
// em NSString do Foundation
let item = NSItemProvider(object: "Arrastando" as NSString)
// Note que retornamos um array pois um _drag_ pode conter múltiplos objetos
return [ UIDragItem(itemProvider: item) ]
}
Drop
Na interação de soltar – em inglês drop – o procedimento é o mesmo, criamos um UIDropInteraction
e o adicionamos na view que receberá o item.
let drop = UIDropInteraction(delegate: self)
containerView.addInteraction(drop)
No delegate UIDropInteractionDelegate
temos o processamento do item a ser recebido. Primeiro vamos ajustar a operação a ser executada quando recebermos um drop, essa configuração altera o ícone que será exibido quando o item for arrastado em cima do alvo do drop.
func dropInteraction(_ interaction: UIDropInteraction, sessionDidUpdate session: UIDropSession) -> UIDropProposal {
// Temos algumas opções (em ordem de mais utilizada para menos):
// - .cancel: cancela o _drag_, não tranfere nenhuma informação;
// - .copy: aceita o _drag_, as informações dos itens devem ser copiadas;
// - .move: aceita o _drag_, as informações devem ser movidas;
// - .forbidden: não aceita o _drag_, apesar de normalmente esse alvo
// aceitar um _drag_, no momento não está aceitando;
return UIDropProposal(operation: .copy)
}
Agora vamos processar o drop. Como o item (ou itens) de origem pode demorar para chegar – pode ser um arquivo grande ou até um download – essa operação é executada em segundo plano.
func dropInteraction(_ interaction: UIDropInteraction, performDrop session: UIDropSession) {
// Usamos o método `loadObjects` para carregar os itens, assim que estiverem
// disponíveis a _closure_ será executada. Como nosso exemplo de _drag_
// passamos uma `NSString`, estamos especificando aqui.
session.loadObjects(ofClass: NSString.self) { itens in
// Vamos transformar a `NSString` em `String` e percorrer
// todos os itens -- caso existam.
for item in itens as! [String] {
print(item)
}
}
}
Exemplo
Preparamos um exemplo completo para você testar.
Crie um projeto iOS e no storyboard adicione uma UILabel
e um UITextView
. NÃO se esqueça de habilitar a propriedade User Interaction Enabled
da label – para poder receber o toque – e utilizar o simulador do iPad.
class ViewController: UIViewController {
@IBOutlet weak var label: UILabel!
@IBOutlet weak var textView: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
let drag = UIDragInteraction(delegate: self)
label.addInteraction(drag)
let drop = UIDropInteraction(delegate: self)
textView.addInteraction(drop)
}
}
extension ViewController: UIDragInteractionDelegate {
func dragInteraction(_ interaction: UIDragInteraction, itemsForBeginning session: UIDragSession) -> [UIDragItem] {
let item = NSItemProvider(object: "Arrastando" as NSString)
return [ UIDragItem(itemProvider: item) ]
}
}
extension ViewController: UIDropInteractionDelegate {
func dropInteraction(_ interaction: UIDropInteraction, sessionDidUpdate session: UIDropSession) -> UIDropProposal {
return UIDropProposal(operation: .copy)
}
func dropInteraction(_ interaction: UIDropInteraction, performDrop session: UIDropSession) {
session.loadObjects(ofClass: NSString.self) { itens in
for item in itens as! [String] {
let texto = self.textView.text + "\n\(item)"
self.textView.text = texto
}
}
}
}
Veja o projeto completo no GitHub.
Até a próxima!
>}