드래그 앤 드롭에 대해서 공부해봅시다
드래그 앤 드롭이 뭐냐면
이런것임ㅇㅇ
아이패드의 경우에는 이렇게 다른앱간으로도 드래그앤드롭이 가능하고 단일앱에서도 드래그앤드롭이 가능함
아이폰은 iOS 15 이전에는 단일앱에서만 가능했지만 iOS 15 이후부턴 다른앱간으로 드래그 앤 드롭이 가능하다함
? 아이폰은 한번에 두개의 앱을 동시에 실행하지 못하는데 어찌가능함 ?
이렇게 가능함
일단 드래그할 앱을 소스앱이라 하고 드롭할 앱을 목적지앱이라 하겠음
일단 소스앱에서 이미지, 텍스트같은 아이템(데이터)을 드래그하게 되면 아이템을 인코딩하여 NSItemProvider 안에 포장하고 이것을 [UIDragItem]으로 다시한번 포장해서 목적지앱에 드롭하면 목적지앱이 포장을 풀고 디코딩하는 방식으로 이루어져있음 (SwiftUI에선 그냥 NSItemProvider배열을 보내는것 같드라...)
이때 소스앱은 Uniform Type Identifier을 제공하여 드래그된 객체의 유형을 정의함
자 여기서 Uniform Type Identifier이 무엇이냐 하면
'A Uniform Type Identifier (UTI) is a text string used on software provided by Apple Inc. to uniquely identify a given class or type of item'
번역하면
'UTI(Uniform Type Identifier)는 주어진 클래스나 항목 유형을 고유하게 식별하기 위해 Apple Inc.가 제공하는 소프트웨어에 사용하는 텍스트 문자열입니다.'
음... 뭔소린지 모르겠음...
그냥 쉽게말해 어떠한 파일의 형식을 식별하는 문자열이라고 생각하면 될듯함
uti 더 알아보기
하여튼 중요한건 이게 아니고 NSItemProvider에 대해서 더 알아보겠음
소스앱에서 데이터를 NSItemProvider에 감싸줄려면 해당 데이터의 클래스에 NSItemProviderWriting이라는 프로토콜을 채택해줘야함
반대로 목적지앱에서 NSItemProvider을 풀어서 디코딩할려면 NSItemProviderReading이란 프로토콜을 채택해줘야함
근데 우리는 이미지를 드래그 앤 드롭 할거잖슴
그런데 NSString, NSAttributedString, NSURL, UIColor, UIImage는
이미 위 두 프로토콜을 채택하고있음 ㄱㅇㄷ
만약 커스텀 클래스를 만들었고 이 클래스를 전달하고싶다면 꼭 위 두 프로토콜을 채택해줘야함
그럼 일단 함 시작해보자
1. drag and drop Interaction 만들기
class ViewController: UIViewController, UIDragInteractionDelegate, UIDropInteractionDelegate {
@IBOutlet weak var imageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let dragInteraction = UIDragInteraction(delegate: self)
let dropInteraction = UIDropInteraction(delegate: self)
imageView.addInteraction(dragInteraction)
imageView.addInteraction(dropInteraction)
imageView.isUserInteractionEnabled = true
}
}
일단 이미지뷰에 dragInteraction이랑 dropInteraction을 추가해줌
여기서 delegate를 self로 해주기때문에 UIDragInteractionDelegate랑 UIDropInteractionDelegate를 채택해줘야함
그리고 필수로 이미지뷰의 isUserInteractionEnabled을 true로 해줘야함
이거 안해주면 이미지뷰는 어떠한 상호작용도 안일어남ㅇㅇ
2. 일단은 드래그먼저
UIDragInteractionDelegate을 채택해주면 필수구현메서드가 하나 있음
func dragInteraction(_ interaction: UIDragInteraction, itemsForBeginning session: UIDragSession) -> [UIDragItem] {
guard let image = imageView.image else { return [] }
let provider = NSItemProvider(object: image)
let item = UIDragItem(itemProvider: provider)
return [item]
}
이 메서드인데 하나하나 뜯어보겠음
아까 드래그를 할때 아이템을 NSItemProvider로 감싼뒤 UIDragItem배열로 한번더 감싸서 리턴한다고 햇잖슴
이 메서드가 하는 일이 그거임
imageView의 이미지를 NSItemProvider의 오브젝트로 넣어준다음 이 provider를 가지고있는 UIDragItem 배열을 리턴해주면 끝임
그럼 이렇게 드래그가 가능해짐
벗 보다시피 드롭은 아직 안되는데 아직 드롭관련 메서드를 구현 안해줘서 그럼
파일앱에서 드롭이 가능한 이유는 드롭관련 메서드가 구현 돼있기때문이겠지
3. 이번엔 드롭
드롭에선 두가지 메서드를 구현해줘야함
func dropInteraction(_ interaction: UIDropInteraction, sessionDidUpdate session: UIDropSession) -> UIDropProposal {
return UIDropProposal(operation: .copy)
}
이 메서드는 아이템이 드롭됐을때 어떻게 처리할건지에 대한 메서드임
operation에 작업유형을 설정할수 잇는데
.cancel - 데이터가 전송되지 않도록 지정하여 드래그를 취소하도록 지정하는 유형
.forbidden - 이동 또는 복사 작업이 일반적으로 가능하지만 드롭을 허용하지 않겠다 하는 유형
.copy - 드래그 항목으로 표시되는 데이터를 대상 보기로 복사하도록 지정하는 유형
.move - 드래그 항목으로 표시되는 데이터를 복사하는 것이 아니라 이동하는 유형
이 있음
func dropInteraction(_ interaction: UIDropInteraction, performDrop session: UIDropSession) {
for item in session.items {
let itemProvider = item.itemProvider
guard itemProvider.canLoadObject(ofClass: UIImage.self) else { continue }
itemProvider.loadObject(ofClass: UIImage.self) { image, _ in
guard let image = image as? UIImage else {
return
}
DispatchQueue.main.async {
self.imageView.image = image
}
}
}
}
두번째 메서드인데 이 메서드는 아이템이 드롭됐을때 처리할 동작들을 구현하는 메서드임
드롭시 데이터가 UIDropSession 타입으로 오는데 이 타입의 items프로퍼티에 소스앱에서 보낸 UIDragItem 배열이 있음
UIDragItem에서 itemProvider을 꺼내고 이 itmeProvider의 데이터를 canLoadObject메서드로 UIImage타입으로 변환할수 있는지 확인을 한다음 변환이 가능하면 변환을 loadObject메서드로 UIImage로 변환시킨다음 imageView의 이미지에 넣어주는 작업을 하고있음
여기서 주의할점은 loadObject는 글로벌큐에서 동작하기 때문에 imageView에 넣어주는 작업은 main큐로 보내서 작업을 해아한다는 점임
하여튼 이 두가지 메서드를 다 구현하면
이렇게 드롭이 가능해지는거임
끝!
전체코드
https://github.com/jmindeveloper/DragAndDrop
참고
https://www.raywenderlich.com/11632532-ipados-multitasking-using-multiple-windows-for-your-app
https://www.raywenderlich.com/3121851-drag-and-drop-tutorial-for-ios
https://zeddios.tistory.com/1024
https://developer.apple.com/documentation/uikit/uidropoperation
'ios 개발 > iOS' 카테고리의 다른 글
[iOS] PhotoKit (2/3) - 사진앱 변경 요청하기 및 변경사항 실시간 동기화 (0) | 2022.05.21 |
---|---|
[iOS] PhotoKit (1/3) - 사진을 받아오기 위해 알아야 하는것 (0) | 2022.05.20 |
[iOS] identifier 쉽게 등록하는법 (0) | 2022.05.19 |
[iOS] 픽셀과 포인트의 차이 (0) | 2022.05.18 |
[iOS] CGPoint, CGSize, CGRect (0) | 2022.05.17 |