Supporting Drag and Drop in Table Views

Panther·2021년 8월 28일
0

https://developer.apple.com/documentation/uikit/views_and_controls/table_views/supporting_drag_and_drop_in_table_views

"Initiate drags and handle drops from a table view."

테이블 뷰로부터 드래그를 시작하고 드롭을 처리합니다.

Overview

테이블 뷰는 표시되는 행과 함께 작동하는 특수한 API를 통해 드래그 앤 드롭을 지원합니다. 드래그를 지원하려면 드래그 딜리게이트 객체(UITableViewDragDelegate 프로토콜을 채택하는 객체)를 정의하고 이 객체를 테이블 뷰의 dragDelegate 속성에 할당해야 합니다. 드롭을 처리하려면 드롭 딜리게이트 객체(UITableViewDropDelegate 프로토콜을 채택하는 객체)를 정의하고 이 객체를 테이블 뷰의 dropDelegate 속성에 할당해야 합니다.

Dragging Rows from the Table View

테이블 뷰는 대부분의 드래그 관련 상호작용을 관리하지만, 어떤 행이 드래그되어야 할지를 구체화할 필요가 있습니다. 드래그 제스쳐가 발생하면 테이블 뷰는 드래그 세션을 생성하고 드래그 딜리게이트 객체의 tableView(_:itemsForBeginning:at:) 메소드를 호출합니다. (사용자가 선택된 행을 드래그하면 이 메소드는 선택의 각 행에 대해 한 번 호출됩니다. 선택된 행이 없으면 메소드는 기본 행에 대해 한 번만 호출됩니다.) 비어있지 않은 배열을 반환하면 테이블 뷰는 구체화한 행들의 드래그를 시작합니다. 특정 인덱스 경로로부터 컨텐트 드래그를 사용자에게 허용하지 않으려면 비어있는 배열을 반환하시기 바랍니다.

Note
추가적인 드래그 관련 상호작용을 관리하려면 UITableViewDragDelegate 프로토콜의 다른 메소드를 사용할 수 있습니다. 예를 들어 드래그되는 행들의 모양을 커스터마이징할 수 있으며, 사용자가 현재 드래그 세션에 아이템을 추가하도록 할 수 있습니다.

tableView(_:itemsForBeginning:at:) 메소드의 구현에서 아래처럼 해야 합니다.

  1. 하나 혹은 하나 이상의 NSItemProvider 객체를 생성합니다. 테이블 행에 대한 데이터를 표시하기 위해 아이템 제공자를 사용해야 합니다.
  2. UIDragItem 객체로 각 아이템 제공자 객체를 감사야 합니다.
  3. 각각의 드래그 아이템의 localObject 속성에 값을 할당하는 것을 고려해야 합니다. 이 단계는 선택적이지만 같은 앱 내부에서 드래그 앤 드로 컨텐트를 더 빠르게 해줍니다.
  4. 메소드로부터 드래그 아이템들을 반환합니다.

드래그 아이템 생성을 하는 행을 결정하기 위해 제공된 인덱스 경로를 사용해야 합니다. 타깃 행이 현재 선택된 행이면 테이블은 자동으로 선택된 행 모두를 드래그합니다. 행이 현재 선택의 부분이 아닌 경우 테이블 뷰는 이미 활성화된 드래그 operation에 현재 선택을 추가합니다.

드래그 시작에 대한 더 많은 정보는 UITableViewDragDelegate를 보시기 바랍니다.

Receiving Dropped Content

컨텐트가 bounds 내부로 드래그되면 테이블 뷰는 드래그된 데이터를 받을 수 있을지 결정하기 위해 드롭 딜리게이트를 참고합니다. 초기에 테이블 뷰는 데이터 소스로 특정 데이터를 통합할 수 있는지를 결정하기 위해 드롭 딜리게이트의 tableView(_:canHandle:) 메소드만을 호출합니다. 데이터를 통합할 수 있으면 테이블 뷰는 데이터를 어디에 드롭시킬 것인지 결정하기 위해 다른 메소드 호출을 시작합니다.

사용자의 손가락이 움직일 때 테이블 뷰는 잠재적 드롭 위치를 추적하고, 각각의 변화에 대해 tableView(_:dropSessionDidUpdate:withDestinationIndexPath:) 메소드를 호출해서 딜리게이트에게 알려줍니다. 이 메소드 구현은 선택적이지만 권장됩니다. 왜냐하면 드래그된 컨텐트가 어떻게 통합될 것인지에 대한 시각적 피드백을 표시할 수 있도록 해주기 때문입니다. 구현에서 특정 인덱스 경로에서 드롭에 대해 어떻게 응답할지에 대한 정보와 함께 UITableViewDropProposal 객체를 생성해야 합니다. 예를 들어 데이터 소스에 새로운 행으로 컨텐트를 삽입하길 원할 수도 있고, 특정 인덱스 경로에 기존 행으로 데이터를 추가하길 원할 수도 있습니다. 메소드는 자주 호출되기 때문에 가능한 빠르게 proposal을 반환해야 합니다. 이 메소들르 구현하지 않는 경우 테이블 뷰는 드롭 처리를 어떻게 해야 하는지에 대한 시각적 피드백을 제공하지 않습니다.

사용자가 스크린으로부터 손가락을 떼서 드롭을 수행하면 테이블 뷰는 드롭 딜리게이트의 tableView(_:performDropWith:) 메소드를 호출합니다. 드롭된 데이터를 처리하려면 이 메소드를 구현해야 합니다. 구현에서 드래그된 데이터를 가져오고, 테이블 뷰의 데이터 소스를 업데이트해야 하며, 테이블 뷰 자체에 모든 필요한 행을 삽입해야 합니다. 컨텐트가 테이블 뷰로부터 기인한 것이라면 현재 위치로부터 드래그된 행을 삭제할 수 있고, 기존 테이블 뷰 API를 사용해서 새 위치에 삽입할 수 있습니다. 컨텐트가 테이블 뷰 밖으로부터 기인한 경우 데이터를 가져오고 삽입하기 위해 localObject 속성(앱 내부에서 기인한 컨텐트의 경우)을 사용하거나 NSItemProvider 객체를 사용할 수 있습니다.

tableView(_:performDropWith:) 메소드의 구현에서 아래처럼 해야 합니다.

  1. 제공된 드롭 조정자 객체에서 items 속성을 반복해야 합니다.
  2. 각 아이템에 대해 컨텐트를 어떻게 처리할지 결장해야 합니다.
    • 아이템의 sourceIndexPath가 값을 포함하는 경우 아이템은 테이블 뷰에서 기인한 것입니다. 현재 위치로부터 아이템을 삭제하기 위해 batch 업데이트를 사용해야 하고, 새 인덱스 경로에 삽입해야 합니다.
    • 드래그 아이템의 localObject 속성이 집합인 경우 컨텐트는 앱 어느 곳으로부터 기인한 것이며, 그렇기 때문에 행을 삽입하거나 기존 아이템을 업데이트해야 합니다.
    • 다른 옵션 사용이 불가능한 경우 드래그 아이템의 itemProvider 속성에서 NSItemProvider를 사용해 데이터를 비동기적으로 가져오고, 아이템을 삽입하거나 업데이트해야 합니다.
  3. 데이터 소스를 업데이트하고 테이블 뷰에서 필수적인 아이템들을 삽입하거나 이동해야 합니다.

컨텐트가 앱에서 이미 로컬인 경우 테이블 뷰의 데이터 소스와 인터페이스를 직접 업데이트할 수 있습니다. 예를 들어 테이블 뷰 내부에서 드래그된 행을 삭제하고 삽입하기 위해 batch 업데이트를 사용할 수 있습니다. 완료되면 테이블 뷰로 드래그된 컨텐트의 삽입 애니메이션 처리를 위해 드롭 조정자의 drop(_:toRowAt:) 메소드를 호출해야 합니다.

NSItemProvider 객체를 사용해서 가져와야 하는 데이터의 경우 실제 데이터를 가져올 수 있을 때까지 테이블 뷰로 플레이스홀더를 삽입해야 합니다. 플레이스호럳를 삽입하는 것은 테이블 뷰로 새로운 행이 삽입할 때에만 필수적입니다. 플레이스홀더는 실제 데이터가 사용 가능해질 때까지 표시하길 원하는 기본값 컨텐트를 나타내면서 임시 행 역할을 합니다. 예를 들어 컨텐트가 현재 로딩중임을 나타내고 있는 텍스트 필드로 플레이스홀더 행을 제공할 수 있습니다.

테이블 뷰에 플레이스홀더를 삽입하려면 아래처럼 해야 합니다.

  1. 테이블 뷰로 플레이스홀더 행을 삽입하려면 제공된 UITableViewDropCoordinator 객체의 drop(_:toPlaceholderInsertedAt:withReuseIdentifier:rowHeight:cellUpdateHandler:) 메소드를 호출해야 합니다. 플레이스홀더 셀의 컨텐츠를 설정하기 위해 cellUpdateHandler 파라미터에 있는 블록을 사용해야 합니다.
  2. NSItemProvider 객체로부터 비동기로 데이터 로딩을 시작해야 합니다.

NSItemProvider 객체가 실제 데이터를 반환하면 삽입을 수행하고 플레이스홀더 셀과 최종 셀을 교환해야 합니다. 구체적으로 플레이스홀더 생성 후에 받은 컨텍스트 객체의 commitInsertion(dataSourceUpdates:) 메소드를 호출해야 합니다. 해당 메소드에 전달한 블록에서 모델 객체를 업데이트해야 하고 테이블 뷰의 데이터 소스를 업데이트해야 합니다. 이 메소드가 반환하면 테이블 뷰는 자동으로 플레이스홀더를 삭제하고 최종 행을 삽입하며, 이는 업데이트된 아이템이 드롭 조정자의 destinationIndexPath 속성에 의해 구체화된 위치에서 새로운 cellInsert 플레이스홀더로 반영될 수 있도록 합니다.

See Also


Drag and Drop

UITableViewDropProposal

테이블 뷰에서 드롭을 처리하기 위한 제안된 해결책입니다.

https://developer.apple.com/documentation/uikit/uitableviewdropproposal
https://velog.io/@panther222128/UITableViewDropProposal


0개의 댓글