Xamarin.iOS에서 끌어서 놓기

iOS 11에 대한 끌어서 놓기 구현

iOS 11에는 iPad의 애플리케이션 간에 데이터를 복사하는 끌어서 놓기 지원이 포함되어 있습니다. 사용자는 나란히 배치된 앱에서 모든 유형의 콘텐츠를 선택하고 끌거나 앱 아이콘 위로 끌어서 앱을 열고 데이터를 삭제할 수 있도록 할 수 있습니다.

Drag and drop example from custom app into Notes app

참고 항목

iOS 15 이전에는 i전화 동일한 앱 내에서만 끌어서 놓기를 사용할 수 있습니다. iOS 15에는 앱 간 끌어서 놓기가 도입되었습니다.

콘텐츠를 만들거나 편집할 수 있는 모든 위치에서 끌어서 놓기 작업을 지원하는 것이 좋습니다.

  • 텍스트 컨트롤은 추가 작업 없이 iOS 11에 대해 빌드된 모든 앱에 대해 끌어서 놓기를 지원합니다.
  • 테이블 뷰 및 컬렉션 뷰에는 끌어서 놓기 동작 추가를 간소화하는 iOS 11의 향상된 기능이 포함되어 있습니다.
  • 추가 사용자 지정을 통해 끌어서 놓기를 지원하기 위해 다른 모든 보기를 만들 수 있습니다.

앱에 끌어서 놓기 지원을 추가할 때 다양한 수준의 콘텐츠 충실도를 제공할 수 있습니다. 예를 들어 수신 앱이 끌기 대상에 가장 적합한 항목을 선택할 수 있도록 서식이 지정된 텍스트와 일반 텍스트 버전의 데이터를 모두 제공할 수 있습니다. 끌기 시각화를 사용자 지정하고 한 번에 여러 항목을 끌 수도 있습니다.

텍스트 컨트롤을 사용하여 끌어서 놓기

UITextView 선택한 UITextField 텍스트를 끌어서 텍스트 콘텐츠를 삭제할 수 있습니다.

UITableView를 사용하여 끌어서 놓기

UITableView 에는 테이블 행과의 끌어서 놓기 상호 작용에 대한 기본 제공 처리가 있으므로 기본 동작을 사용하도록 설정하는 몇 가지 방법만 있으면 됩니다.

관련된 두 가지 인터페이스가 있습니다.

  • IUITableViewDragDelegate – 테이블 뷰에서 끌기가 시작될 때 정보를 패키지합니다.
  • IUITableViewDropDelegate – 삭제를 시도하고 완료할 때 정보를 처리합니다.

DragAndDropTableView 샘플에서 이러한 두 인터페이스는 모두 대리자 및 데이터 원본과 함께 클래스에서 UITableViewController 구현됩니다. 메서드에 할당됩니다.ViewDidLoad

this.TableView.DragDelegate = this;
this.TableView.DropDelegate = this;

이러한 두 인터페이스에 필요한 최소 코드는 아래에 설명되어 있습니다.

테이블 뷰 끌기 대리자

테이블 뷰에서 행 끌기를 지원하는 데 필요한 유일한 방법은 .입니다GetItemsForBeginningDragSession. 사용자가 행을 끌기 시작하면 이 메서드가 호출됩니다.

구현은 다음과 같습니다. 끌어서 놓기 행과 연결된 데이터를 검색하고 인코딩하고 애플리케이션이 작업의 "삭제" 부분을 처리하는 방법을 결정하는 방법을 구성 NSItemProvider 합니다(예: 예제에서 데이터 형식 PlainText을 처리할 수 있는지 여부).

public UIDragItem[] GetItemsForBeginningDragSession (UITableView tableView,
  IUIDragSession session, NSIndexPath indexPath)
{
  // gets the 'information' to be dragged
  var placeName = model.PlaceNames[indexPath.Row];
  // convert to NSData representation
  var data = NSData.FromString(placeName, NSStringEncoding.UTF8);
  // create an NSItemProvider to describe the data
  var itemProvider = new NSItemProvider();
  itemProvider.RegisterDataRepresentation(UTType.PlainText,
                                NSItemProviderRepresentationVisibility.All,
                                (completion) =>
  {
    completion(data, null);
    return null;
  });
  // wrap in a UIDragItem
  return new UIDragItem[] { new UIDragItem(itemProvider) };
}

끌기 대리자의 선택적 메서드는 대상 앱에서 활용할 수 있는 여러 데이터 표현(예: 서식이 지정된 텍스트, 일반 텍스트, 드로잉의 벡터 및 비트맵 버전)을 제공하는 등 끌기 동작을 사용자 지정하기 위해 구현할 수 있는 많은 선택적 메서드가 있습니다. 동일한 앱 내에서 끌어서 놓을 때 사용할 사용자 지정 데이터 표현을 제공할 수도 있습니다.

테이블 뷰 놓기 대리자

끌어서 놓기 대리자의 메서드는 테이블 뷰 위에 끌기 작업이 발생하거나 그 위에 완료할 때 호출됩니다. 필요한 메서드는 데이터를 삭제할 수 있는지 여부와 삭제가 완료될 경우 수행되는 작업을 결정합니다.

  • CanHandleDropSession – 끌기가 진행 중이고 잠재적으로 애플리케이션에서 삭제되는 동안 이 메서드는 끌어서 놓는 데이터를 삭제할 수 있는지 여부를 결정합니다.
  • DropSessionDidUpdate – 끌기가 진행되는 동안 이 메서드를 호출하여 의도된 작업을 결정합니다. 끌어서 놓는 테이블 뷰의 정보, 끌기 세션 및 가능한 인덱스 경로를 모두 사용하여 사용자에게 제공된 동작 및 시각적 피드백을 확인할 수 있습니다.
  • PerformDrop – 사용자가 손가락을 떼어 놓기를 완료하면 이 메서드는 끌어서 놓는 데이터를 추출하고 테이블 뷰를 수정하여 새 행(또는 행)에 데이터를 추가합니다.

CanHandleDropSession

CanHandleDropSession 는 테이블 뷰에서 끌어서 놓는 데이터를 허용할 수 있는지 여부를 나타냅니다. 이 코드 조각 CanLoadObjects 에서는 이 테이블 뷰가 문자열 데이터를 허용할 수 있는지 확인하는 데 사용됩니다.

public bool CanHandleDropSession(UITableView tableView, IUIDropSession session)
{
  return session.CanLoadObjects(typeof(NSString));
}

DropSessionDidUpdate

DropSessionDidUpdate 끌기 작업이 진행되는 동안 메서드가 반복적으로 호출되어 사용자에게 시각적 신호를 제공합니다.

아래 HasActiveDrag 코드에서는 작업이 현재 테이블 뷰에서 시작되었는지 여부를 확인하는 데 사용됩니다. 이 경우 단일 행만 이동할 수 있습니다. 끌기가 다른 원본에서 온 경우 복사 작업이 표시됩니다.

public UITableViewDropProposal DropSessionDidUpdate(UITableView tableView, IUIDropSession session, NSIndexPath destinationIndexPath)
{
  // The UIDropOperation.Move operation is available only for dragging within a single app.
  if (tableView.HasActiveDrag)
  {
    if (session.Items.Length > 1)
    {
        return new UITableViewDropProposal(UIDropOperation.Cancel);
    } else {
        return new UITableViewDropProposal(UIDropOperation.Move, UITableViewDropIntent.InsertAtDestinationIndexPath);
    }
  } else {
    return new UITableViewDropProposal(UIDropOperation.Copy, UITableViewDropIntent.InsertAtDestinationIndexPath);
  }
}

놓기 작업은 , Move또는 Copy. 중 Cancel하나일 수 있습니다.

삭제 의도는 새 행을 삽입하거나 기존 행에 데이터를 추가/추가하는 것입니다.

PerformDrop

PerformDrop 메서드는 사용자가 작업을 완료하고 테이블 뷰 및 데이터 원본을 수정하여 삭제된 데이터를 반영할 때 호출됩니다.

public void PerformDrop(UITableView tableView, IUITableViewDropCoordinator coordinator)
{
  NSIndexPath indexPath, destinationIndexPath;
  if (coordinator.DestinationIndexPath != null)
  {
    indexPath = coordinator.DestinationIndexPath;
    destinationIndexPath = indexPath;
  }
  else
  {
    // Get last index path of table view
    var section = tableView.NumberOfSections() - 1;
    var row = tableView.NumberOfRowsInSection(section);
    destinationIndexPath = NSIndexPath.FromRowSection(row, section);
  }
  coordinator.Session.LoadObjects(typeof(NSString), (items) =>
  {
    // Consume drag items
    List<string> stringItems = new List<string>();
    foreach (var i in items)
    {
      var q = NSString.FromHandle(i.Handle);
      stringItems.Add(q.ToString());
    }
    var indexPaths = new List<NSIndexPath>();
    for (var j = 0; j < stringItems.Count; j++)
    {
      var indexPath1 = NSIndexPath.FromRowSection(destinationIndexPath.Row + j, destinationIndexPath.Section);
      model.AddItem(stringItems[j], indexPath1.Row);
      indexPaths.Add(indexPath1);
    }
    tableView.InsertRows(indexPaths.ToArray(), UITableViewRowAnimation.Automatic);
  });
}

큰 데이터 개체를 비동기적으로 로드하기 위해 추가 코드를 추가할 수 있습니다.

끌어서 놓기 테스트

샘플을 테스트하려면 iPad를 사용해야 합니다. 다른 앱(예: 메모)과 함께 샘플을 열고 행과 텍스트를 끌어다 놓습니다.

screenshot of drag operation in progress